Skip to content

Commit 3196dfc

Browse files
authored
Merge pull request #202 from pheuberger/cronjob-safe-queue
Run cron job to start Safe signature requests queue processing
2 parents 87817a4 + 4baee53 commit 3196dfc

File tree

6 files changed

+84
-33
lines changed

6 files changed

+84
-33
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"kysely": "^0.27.4",
6363
"lodash": "^4.17.21",
6464
"lru-cache": "^11.0.0",
65+
"node-cron": "^3.0.3",
6566
"pg": "^8.12.0",
6667
"reflect-metadata": "^0.2.2",
6768
"rollup": "^4.12.0",
@@ -93,6 +94,7 @@
9394
"@swc/cli": "^0.3.12",
9495
"@swc/core": "^1.4.15",
9596
"@types/body-parser": "^1.19.5",
97+
"@types/node-cron": "^3.0.11",
9698
"@types/pg": "^8.11.6",
9799
"@types/sinon": "^17.0.2",
98100
"@types/swagger-ui-express": "^4.1.6",

pnpm-lock.yaml

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/controllers/SignatureRequestController.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111

1212
import { SupabaseDataService } from "../services/SupabaseDataService.js";
1313
import { verifyAuthSignedData } from "../utils/verifyAuthSignedData.js";
14-
import { SignatureRequestProcessor } from "../services/SignatureRequestProcessor.js";
14+
import SignatureRequestProcessor from "../services/SignatureRequestProcessor.js";
1515

1616
interface CancelSignatureRequest {
1717
signature: string;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import cron from "node-cron";
2+
3+
import SignatureRequestProcessor from "../services/SignatureRequestProcessor.js";
4+
5+
export default class SignatureRequestProcessorCron {
6+
private static instance: SignatureRequestProcessorCron;
7+
private processor: SignatureRequestProcessor;
8+
9+
private constructor() {
10+
this.processor = SignatureRequestProcessor.getInstance();
11+
this.setupCronJob();
12+
}
13+
14+
private setupCronJob() {
15+
// Run every 30 seconds
16+
cron.schedule("*/30 * * * * *", async () => {
17+
try {
18+
await this.processor.processPendingRequests();
19+
} catch (error) {
20+
console.error("Error in signature request processor cron job:", error);
21+
}
22+
});
23+
}
24+
25+
public static start(): void {
26+
if (!SignatureRequestProcessorCron.instance) {
27+
SignatureRequestProcessorCron.instance =
28+
new SignatureRequestProcessorCron();
29+
}
30+
}
31+
}

src/index.ts

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,61 @@
1-
import './instrument.js';
2-
import express, {type Express} from "express";
1+
import "./instrument.js";
2+
import express, { type Express } from "express";
33
import "reflect-metadata";
44
import cors from "cors";
5-
import {assertExists} from "./utils/assertExists.js";
6-
import {yoga} from "./client/graphql.js";
5+
import { assertExists } from "./utils/assertExists.js";
6+
import { yoga } from "./client/graphql.js";
77
import swaggerUi from "swagger-ui-express";
8-
import swaggerJson from "./__generated__/swagger.json" assert {type: "json"}
9-
import {RegisterRoutes} from "./__generated__/routes/routes.js";
10-
import * as Sentry from '@sentry/node';
8+
import swaggerJson from "./__generated__/swagger.json" assert { type: "json" };
9+
import { RegisterRoutes } from "./__generated__/routes/routes.js";
10+
import * as Sentry from "@sentry/node";
11+
import SignatureRequestProcessorCron from "./cron/SignatureRequestProcessing.js";
1112

1213
// @ts-expect-error BigInt is not supported by JSON
1314
BigInt.prototype.toJSON = function () {
14-
const int = Number.parseInt(this.toString());
15-
return int ?? this.toString();
15+
const int = Number.parseInt(this.toString());
16+
return int ?? this.toString();
1617
};
1718

1819
// @ts-expect-error BigInt is not supported by JSON
1920
BigInt.prototype.fromJSON = function () {
20-
return BigInt(this.toString());
21+
return BigInt(this.toString());
2122
};
2223

2324
const PORT = assertExists(process.env.PORT, "PORT");
2425

2526
const app: Express = express();
2627

27-
app.use(express.urlencoded({extended: true, limit: '1mb'}));
28-
app.use(express.json({limit: '1mb'}));
28+
app.use(express.urlencoded({ extended: true, limit: "1mb" }));
29+
app.use(express.json({ limit: "1mb" }));
2930
app.use(cors());
3031

31-
app.get('/health', (req, res) => {
32-
const data = {
33-
uptime: process.uptime(),
34-
message: 'OK',
35-
date: new Date()
36-
}
32+
app.get("/health", (req, res) => {
33+
const data = {
34+
uptime: process.uptime(),
35+
message: "OK",
36+
date: new Date(),
37+
};
3738

38-
res.status(200).send(data);
39+
res.status(200).send(data);
3940
});
4041

4142
// Bind GraphQL Yoga to the graphql endpoint to avoid rendering the playground on any path
4243
app.use(yoga.graphqlEndpoint, yoga);
4344

44-
app.use(
45-
"/spec",
46-
swaggerUi.serve,
47-
swaggerUi.setup(swaggerJson)
48-
);
45+
app.use("/spec", swaggerUi.serve, swaggerUi.setup(swaggerJson));
4946

5047
RegisterRoutes(app);
5148

5249
// The error handler must be registered before any other error middleware and after all controllers
5350
Sentry.setupExpressErrorHandler(app);
5451

55-
app.listen(PORT, () => {
56-
console.log(
57-
`🕸️ Running a GraphQL API server at http://localhost:${PORT}/v1/graphql`
58-
);
52+
// Start Safe signature request processing cron job
53+
SignatureRequestProcessorCron.start();
5954

60-
console.log(`🚀 Running Swagger docs at http://localhost:${PORT}/spec`);
55+
app.listen(PORT, () => {
56+
console.log(
57+
`🕸️ Running a GraphQL API server at http://localhost:${PORT}/v1/graphql`,
58+
);
6159

60+
console.log(`🚀 Running Swagger docs at http://localhost:${PORT}/spec`);
6261
});
63-

src/services/SignatureRequestProcessor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { SafeApiQueue } from "./SafeApiQueue.js";
88
type SignatureRequest =
99
Database["public"]["Tables"]["signature_requests"]["Row"];
1010

11-
export class SignatureRequestProcessor {
11+
export default class SignatureRequestProcessor {
1212
private static instance: SignatureRequestProcessor;
1313

1414
private readonly dataService: SupabaseDataService;
@@ -22,7 +22,7 @@ export class SignatureRequestProcessor {
2222
async processPendingRequests(): Promise<void> {
2323
const pendingRequests = await this.getPendingRequests();
2424

25-
console.log(`Found ${pendingRequests.length} pending requests`);
25+
console.log(`Found ${pendingRequests.length} pending signature requests`);
2626

2727
for (const request of pendingRequests) {
2828
const command = getCommand(request);

0 commit comments

Comments
 (0)