Created
July 19, 2022 08:26
-
-
Save lawrencecchen/84ab8bebb9d1c4079634493033f48059 to your computer and use it in GitHub Desktop.
A Typescript first queue/job/schedule engine.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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: "[email protected]", | |
}); | |
}, | |
}); | |
// ========== 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