-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Expand file tree
/
Copy pathnode-cron.ts
More file actions
89 lines (82 loc) · 2.86 KB
/
Copy pathnode-cron.ts
File metadata and controls
89 lines (82 loc) · 2.86 KB
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
import { captureException, type MonitorConfig, withMonitor } from '@sentry/core';
import { replaceCronNames } from './common';
export interface NodeCronOptions {
name: string;
timezone?: string;
}
export interface NodeCron {
schedule: (
cronExpression: string,
callback: (context?: unknown) => void,
options: NodeCronOptions | undefined,
) => unknown;
}
/**
* Wraps the `node-cron` library with check-in monitoring.
*
* ```ts
* import * as Sentry from "@sentry/node";
* import * as cron from "node-cron";
*
* const cronWithCheckIn = Sentry.cron.instrumentNodeCron(cron);
*
* cronWithCheckIn.schedule(
* "* * * * *",
* () => {
* console.log("running a task every minute");
* },
* { name: "my-cron-job" },
* );
* ```
*/
export function instrumentNodeCron<T>(
lib: Partial<NodeCron> & T,
monitorConfig: Pick<MonitorConfig, 'isolateTrace'> = {},
): T {
return new Proxy(lib, {
get(target, prop) {
if (prop === 'schedule' && target.schedule) {
// When 'get' is called for schedule, return a proxied version of the schedule function
return new Proxy(target.schedule, {
apply(target, thisArg, argArray: Parameters<NodeCron['schedule']>) {
const [expression, callback, options] = argArray;
const name = options?.name;
const timezone = options?.timezone;
if (!name) {
throw new Error('Missing "name" for scheduled job. A name is required for Sentry check-in monitoring.');
}
const monitoredCallback = async (...args: Parameters<typeof callback>): Promise<void> => {
return withMonitor(
name,
async () => {
// We have to manually catch here and capture the exception because node-cron swallows errors
// https://github.com/node-cron/node-cron/issues/399
try {
// oxlint-disable-next-line typescript/await-thenable, typescript/return-await -- callback may be async at runtime; awaiting inside the try lets us capture its rejection
return await callback(...args);
} catch (e) {
captureException(e, {
mechanism: {
handled: false,
type: 'auto.function.node-cron.instrumentNodeCron',
},
});
throw e;
}
},
{
schedule: { type: 'crontab', value: replaceCronNames(expression) },
timezone,
...monitorConfig,
},
);
};
return target.apply(thisArg, [expression, monitoredCallback, options]);
},
});
} else {
return target[prop as keyof T];
}
},
});
}