Skip to content

Instantly share code, notes, and snippets.

@lawrencecchen
Created July 19, 2022 08:26
Show Gist options
  • Save lawrencecchen/84ab8bebb9d1c4079634493033f48059 to your computer and use it in GitHub Desktop.
Save lawrencecchen/84ab8bebb9d1c4079634493033f48059 to your computer and use it in GitHub Desktop.
A Typescript first queue/job/schedule engine.
// i like trpc. i like autocomplete. i like vercel/serverless.
// netlify acquired quirrel.
// theo would shill for a type safe option.
// there's a gap for a type-safe scheduling/cron/queuing/realtime and i want to fill it.
// also, quirrel has weird syntax for
// framing: typescript-first bindings for what you would typically use redis for
const appRouter = createRouter();
const queueRouter = createRouter()
.middleware(({ ctx, next }) => {
verifySigningKey(ctx);
return next();
})
// do queues count as queries or mutations?
.query("queue.sendWelcomeMail", {
input: z.object({
to: z.string().min(1),
}),
async resolve({ input }) {
await sendMail(input.to);
},
})
.query("queue.bookingReminder", {
input: z.object({
bookingId: z.string().min(1),
}),
async resolve({ input }) {
const booking = getBooking(input.bookingId);
await sendSms({
to: booking.user.phoneNumber,
body: `Put on your dancing shoes for ${booking.event.title} 🕺`,
});
},
});
export type AppRouter = typeof appRouter;
// ========== Delayed jobs ==========
const client = createTinySyncClient<AppRouter>();
appRouter.mutation("bookings.create", {
input: z.object({
userId: z.string(),
time: z.date(),
}),
async resolve() {
// the scheduling part:
await client.schedule({ delay: "24h" }).query("jobs.bookingReminder", {
to: "foobar@barfoo.com",
});
},
});
// ========== Delayed jobs ==========
// /pages/api/auth/[..nextauth].js
export default NextAuth({
providers: [
// ...
],
events: {
async createUser({ user }) {
// the scheduling part (queue.sendWelcomeMail is a trpc query)
await client.schedule({ delay: "24h" }).query("queue.sendWelcomeMail", {
to: user.email,
});
},
},
});
// ========== Cron jobs ==========
// [...tinycron].ts, tinycron/$.ts, etc.
const cronServer = createCronServer<AppRouter>();
cronServer.cron("0 0 1 * *").query("queue.monthly-invoice");
// logic defined in trpc query
// ========== next.js ==========
export default createNextHandler(cronServer);
// ========== remix ==========
export const { loader, action } = createRemixHandler(cronServer);
// others...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment