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 1717 "dependencies" : {
1818 "@nestjs/common" : " ^10.0.0" ,
1919 "@nestjs/core" : " ^10.0.0" ,
20+ "@nestjs/schedule" : " ^4.1.0" ,
2021 "@nestjs/platform-express" : " ^10.0.0" ,
2122 "@sentry/nestjs" : " latest || *" ,
2223 "@sentry/types" : " latest || *" ,
Original file line number Diff line number Diff line change @@ -79,6 +79,11 @@ export class AppController1 {
7979 async testSpanDecoratorSync ( ) {
8080 return { result : await this . appService . testSpanDecoratorSync ( ) } ;
8181 }
82+
83+ @Get ( 'kill-test-cron' )
84+ async killTestCron ( ) {
85+ this . appService . killTestCron ( ) ;
86+ }
8287}
8388
8489@Controller ( )
Original file line number Diff line number Diff line change 11import { Module } from '@nestjs/common' ;
2+ import { ScheduleModule } from '@nestjs/schedule' ;
23import { AppController1 , AppController2 } from './app.controller' ;
34import { AppService1 , AppService2 } from './app.service' ;
45
56@Module ( {
6- imports : [ ] ,
7+ imports : [ ScheduleModule . forRoot ( ) ] ,
78 controllers : [ AppController1 ] ,
89 providers : [ AppService1 ] ,
910} )
Original file line number Diff line number Diff line change 11import { HttpException , HttpStatus , Injectable } from '@nestjs/common' ;
2+ import { Cron , SchedulerRegistry } from '@nestjs/schedule' ;
23import * 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' ;
46import { makeHttpRequest } from './utils' ;
57
8+ const monitorConfig : MonitorConfig = {
9+ schedule : {
10+ type : 'crontab' ,
11+ value : '* * * * *' ,
12+ } ,
13+ } ;
14+
615@Injectable ( )
716export class AppService1 {
17+ constructor ( private schedulerRegistry : SchedulerRegistry ) { }
18+
819 testSuccess ( ) {
920 return { version : 'v1' } ;
1021 }
@@ -95,6 +106,21 @@ export class AppService1 {
95106 async testSpanDecoratorSync ( ) {
96107 return this . getString ( ) ;
97108 }
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+ }
98124}
99125
100126@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';
33export { init } from './sdk' ;
44
55export { SentryTraced } from './span-decorator' ;
6+ export { SentryCron } from './cron-decorator' ;
You can’t perform that action at this time.
0 commit comments