Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | import type BetterSqlite3Database from "better-sqlite3"; import { type ExtractTablesWithRelations, and, lte, or } from "drizzle-orm"; import { eq } from "drizzle-orm"; import { asc } from "drizzle-orm"; import { isNull } from "drizzle-orm"; import { type BaseSQLiteDatabase, int, sqliteTable, text, } from "drizzle-orm/sqlite-core"; import { type DefineTaskOpts, type PersistedTask, type Task, type TaskStorage, composePersistedTask, defineTaskWithAdapter, } from "./task"; const tasks = sqliteTable("tasks", { id: text("id").primaryKey(), name: text("name").notNull(), data: text("data", { mode: "json" }), created: int("created").notNull(), failedLast: int("failed_last"), failedNr: int("failed_nr"), failedError: text("failed_error"), }); // internal check const _ = tasks.$inferSelect satisfies PersistedTask<unknown>; const schema = { tasks }; export type Database = BaseSQLiteDatabase< "sync", BetterSqlite3Database.RunResult, typeof schema, ExtractTablesWithRelations<typeof schema> >; function composeDatabaseAdapter(database: Database): TaskStorage<unknown> { return { async enqueue({ data, name }) { const persistedTask = composePersistedTask({ data, name }); await database.insert(tasks).values(persistedTask); }, async fetch({ name: taskName, batchSize, maxRetries, retryIntervall }) { const tasks = await database.query.tasks.findMany({ limit: batchSize, orderBy: ({ created }) => asc(created), where: ({ failedNr, failedLast, name }) => and( or(lte(failedNr, maxRetries), isNull(failedNr)), or( lte(failedLast, Date.now() - retryIntervall), isNull(failedLast), ), eq(name, taskName), ), }); return tasks; }, async success({ task }) { await database.delete(tasks).where(eq(tasks.id, task.id)); }, async failure({ task, err }) { await database .update(tasks) .set({ failedLast: Date.now(), failedNr: (task.failedNr ?? 0) + 1, failedError: JSON.stringify({ instance: (err as Error).constructor.name, message: (err as Error).message, stack: (err as Error).stack, }), }) .where(eq(tasks.id, task.id)); }, }; } export function defineDatabaseTask<T>( database: Database, opts: DefineTaskOpts<T>, ): Task<T> { return defineTaskWithAdapter( composeDatabaseAdapter(database), opts as DefineTaskOpts<unknown>, ); } |