File tree Expand file tree Collapse file tree 7 files changed +94
-2
lines changed
dev-packages/e2e-tests/test-applications/nestjs Expand file tree Collapse file tree 7 files changed +94
-2
lines changed Original file line number Diff line number Diff line change 17
17
"dependencies" : {
18
18
"@nestjs/common" : " ^10.0.0" ,
19
19
"@nestjs/core" : " ^10.0.0" ,
20
+ "@nestjs/schedule" : " ^4.1.0" ,
20
21
"@nestjs/platform-express" : " ^10.0.0" ,
21
22
"@sentry/nestjs" : " latest || *" ,
22
23
"@sentry/types" : " latest || *" ,
Original file line number Diff line number Diff line change @@ -79,6 +79,11 @@ export class AppController1 {
79
79
async testSpanDecoratorSync ( ) {
80
80
return { result : await this . appService . testSpanDecoratorSync ( ) } ;
81
81
}
82
+
83
+ @Get ( 'kill-test-cron' )
84
+ async killTestCron ( ) {
85
+ this . appService . killTestCron ( ) ;
86
+ }
82
87
}
83
88
84
89
@Controller ( )
Original file line number Diff line number Diff line change 1
1
import { Module } from '@nestjs/common' ;
2
+ import { ScheduleModule } from '@nestjs/schedule' ;
2
3
import { AppController1 , AppController2 } from './app.controller' ;
3
4
import { AppService1 , AppService2 } from './app.service' ;
4
5
5
6
@Module ( {
6
- imports : [ ] ,
7
+ imports : [ ScheduleModule . forRoot ( ) ] ,
7
8
controllers : [ AppController1 ] ,
8
9
providers : [ AppService1 ] ,
9
10
} )
Original file line number Diff line number Diff line change 1
1
import { HttpException , HttpStatus , Injectable } from '@nestjs/common' ;
2
+ import { Cron , SchedulerRegistry } from '@nestjs/schedule' ;
2
3
import * as Sentry from '@sentry/nestjs' ;
3
- import { SentryTraced } from '@sentry/nestjs' ;
4
+ import { SentryCron , SentryTraced } from '@sentry/nestjs' ;
5
+ import type { MonitorConfig } from '@sentry/types' ;
4
6
import { makeHttpRequest } from './utils' ;
5
7
8
+ const monitorConfig : MonitorConfig = {
9
+ schedule : {
10
+ type : 'crontab' ,
11
+ value : '* * * * *' ,
12
+ } ,
13
+ } ;
14
+
6
15
@Injectable ( )
7
16
export class AppService1 {
17
+ constructor ( private schedulerRegistry : SchedulerRegistry ) { }
18
+
8
19
testSuccess ( ) {
9
20
return { version : 'v1' } ;
10
21
}
@@ -95,6 +106,21 @@ export class AppService1 {
95
106
async testSpanDecoratorSync ( ) {
96
107
return this . getString ( ) ;
97
108
}
109
+
110
+ /*
111
+ Actual cron schedule differs from schedule defined in config because Sentry
112
+ only supports minute granularity, but we don't want to wait (worst case) a
113
+ full minute for the tests to finish.
114
+ */
115
+ @Cron ( '*/5 * * * * *' , { name : 'test-cron-job' } )
116
+ @SentryCron ( 'test-cron-slug' , monitorConfig )
117
+ async testCron ( ) {
118
+ console . log ( 'Test cron!' ) ;
119
+ }
120
+
121
+ async killTestCron ( ) {
122
+ this . schedulerRegistry . deleteCronJob ( 'test-cron-job' ) ;
123
+ }
98
124
}
99
125
100
126
@Injectable ( )
Original file line number Diff line number Diff line change
1
+ import { expect , test } from '@playwright/test' ;
2
+ import { waitForEnvelopeItem } from '@sentry-internal/test-utils' ;
3
+
4
+ test ( 'Cron job triggers send of in_progress envelope' , async ( { baseURL } ) => {
5
+ const inProgressEnvelopePromise = waitForEnvelopeItem ( 'nestjs' , envelope => {
6
+ return envelope [ 0 ] . type === 'check_in' ;
7
+ } ) ;
8
+
9
+ const inProgressEnvelope = await inProgressEnvelopePromise ;
10
+
11
+ expect ( inProgressEnvelope [ 1 ] ) . toEqual (
12
+ expect . objectContaining ( {
13
+ check_in_id : expect . any ( String ) ,
14
+ monitor_slug : 'test-cron-slug' ,
15
+ status : 'in_progress' ,
16
+ environment : 'qa' ,
17
+ monitor_config : {
18
+ schedule : {
19
+ type : 'crontab' ,
20
+ value : '* * * * *' ,
21
+ } ,
22
+ } ,
23
+ contexts : {
24
+ trace : {
25
+ span_id : expect . any ( String ) ,
26
+ trace_id : expect . any ( String ) ,
27
+ } ,
28
+ } ,
29
+ } ) ,
30
+ ) ;
31
+
32
+ // kill cron so tests don't get stuck
33
+ await fetch ( `${ baseURL } /kill-test-cron` ) ;
34
+ } ) ;
Original file line number Diff line number Diff line change
1
+ import * as Sentry from '@sentry/node' ;
2
+ import type { MonitorConfig } from '@sentry/types' ;
3
+
4
+ /**
5
+ * A decorator wrapping the native nest Cron decorator, sending check-ins to Sentry.
6
+ */
7
+ export const SentryCron = ( monitorSlug : string , monitorConfig ?: MonitorConfig ) : MethodDecorator => {
8
+ return ( target : unknown , propertyKey , descriptor : PropertyDescriptor ) => {
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
+ const originalMethod = descriptor . value as ( ...args : any [ ] ) => Promise < any > ;
11
+
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ descriptor . value = function ( ...args : any [ ] ) {
14
+ return Sentry . withMonitor (
15
+ monitorSlug ,
16
+ ( ) => {
17
+ return originalMethod . apply ( this , args ) ;
18
+ } ,
19
+ monitorConfig ,
20
+ ) ;
21
+ } ;
22
+ return descriptor ;
23
+ } ;
24
+ } ;
Original file line number Diff line number Diff line change @@ -3,3 +3,4 @@ export * from '@sentry/node';
3
3
export { init } from './sdk' ;
4
4
5
5
export { SentryTraced } from './span-decorator' ;
6
+ export { SentryCron } from './cron-decorator' ;
You can’t perform that action at this time.
0 commit comments