OnQueueError not firing on task queue: NestJS + Bull - nestjs

I've noticed that bull does not print exceptions to the console by default. To get around this I want to catch errors with the #OnQuerueError decorator and print them to the console (for now). My current implementation does not work and I don't understand why. The handler is not called. I verified that other event listeners work such as #OnQueueActive():
#Processor('email')
export default class DigestEmailProcessor {
constructor(
) {}
#OnQueueError()
handler() {
console.log('fired exception');
}
#Process(PROCESS_NAMES.email.send)
async send(job: Job<JobData>) {
throw new Error("Foo bar")
}
}

The event listener #OnQueueError() is not correct for this use case.
Try using the event listener #OnQueueFailed() this raises an event for jobs that have thrown an error.
using your example code:
#Processor('email')
export default class DigestEmailProcessor {
constructor(
) {}
#OnQueueFailed()
handler(job: Job, error: Error) {
console.log('fired exception');
}
#Process(PROCESS_NAMES.email.send)
async send(job: Job<JobData>) {
throw new Error("Foo bar")
}
}
more information on the different event listeners

Related

rxjs how to handle error in subscriber's next

I'm using rxjs in a library to expose an Observable that clients can subscribe to to consume messages. I want to be able to react appropriately if the subscriber's next function throws an error. However, I'm not seeing any obvious way to detect that. For example:
const observable = new Observable<string>((subscriber) => {
subscriber.next('first')
subscriber.next('second')
subscriber.complete()
})
observable.subscribe(() => {
throw new Error('oh no!')
})
I have tried all of the following, but the errors are bubbled all the way up to a global scope that's surfaced either in an onUnhandledError function provided to the global config, or in absence of that, the node process's unhandledException event.
process.on('uncaughtException', (error) => {
console.error('IN UNCAUGHT EXCEPTION HANDLER', error.message)
})
export function main() {
try {
const observable = new Observable<string>((subscriber) => {
try {
subscriber.next('first')
} catch (error) {
console.error('IN OBSERVABLE CATCH', error.message)
}
subscriber.complete()
}).pipe(
catchError((error) => {
console.error('CATCHERROR PIPE', error.message)
return of('there was an error!!!!')
}),
)
observable.subscribe({
next: (_value) => {
throw new Error('oh no!')
},
error: (error) => {
console.error('IN OBSERVER ERROR HANDLER', error.message)
},
complete: () => console.log('complete!'),
})
} catch (error) {
console.error('IN MAIN CATCH', error.message)
}
}
This logs:
complete!
IN UNCAUGHT EXCEPTION HANDLER oh no!
The docs don't make a big fuss about ensuring that subscribers avoid throwing errors at all costs, but I don't see a standard mechanism for handling it short of some sort of "observer wrapper" (that gets a bit ugly with the overloads).
Turns out that there is effectively no way to handle errors from observers.
When using Observable.subscribe, it wraps your observer functions in a "SafeSubscriber". This then wraps the supplied functions with a ConsumerObserver. This wraps each in a try/catch that, upon errors, either:
sends them to an optional onUnhandledError function you can supply to the rxjs config
sends them "into the ether" to be picked up by the node process
There is no context, and no way to hook into it. Effectively, errors from next, error, or complete handlers just silently disappear.

How to receive socket events inside a flutterBackgroundServices method [FLUTTER]

I am using a server in node js to run socket.io, what i want to do is that when the app is in the background it still receive events from the sockets, can only send events, but does not receive them.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
socketConnection.socket.connect();
await FlutterBackgroundService.initialize(onStart); //here start executing the onStart method
runApp(MyApp());
}
onStart() async {
WidgetsFlutterBinding.ensureInitialized();
final service = FlutterBackgroundService();
if (await service.isServiceRunning()) {
socketEvents();//socket events method
}
}
socketEvents() {
log(socketConnection.socket.connected.toString()); //here I want to know if it is connected and it always shows me **false**, but it does connect
socketConnection.socket.on('noty_event', (data) async {
log(data['msg'].toString()); //I want to show in the console when an event arrives but it does not show anything
});
}

NestJS - async operation inside error filter

In our NestJS-app we've set up a custom error filter, that catches a certain type of error. For those errors we need to perform a request to elasticsearch in order to log the corresponding error information. Since the elasticsearch request is async I've defined the catch method async:
#Catch(MyExceptionType)
#Injectable()
export class MyExceptionFilter implements ExceptionFilter {
constructor(private readonly elasticsearchService: ElasticsearchService) { }
async catch(exception: MyExceptionType, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const request = ctx.getRequest<MyRequestModel>();
const response = ctx.getResponse<MyResponseModel>();
const elasticSearchPayload = PayloadBuilder.of(request, exception);
await this.elasticsearchService.report(elasticSearchPayload);
// ...
response.status(exception.getStatus()).json({...});
}
}
Now - so far this works fine, but I'm wondering if this is actually ok to do, as the ExceptionFilter interface strictly declares catch to be a synchronous method.
Could we run into trouble doing this?
ExceptionFilters are to define your error handling logic. I don't think it should be an issue having it async, Nest just won't wait for the logic to finish, however, it shouldn't invoke any other exception handlers due to how it's custom filter code is written.

NestJS handle service exceptions

I'm working on a NestJS app where my services are not always called by a controller or any http request at all. Rather some services are called by a cron schedule to periodically fetch data.
What would be the best way to handle errors in this scenario? I implemented a "catch-all" exception filter, but when my service is called "internally" (not by a controller/request), there error does not get caught and I have an uncaught promise error.
See my question here: Use global nest module in decorator
This decorator catches errors of a class method and logs them. The logging part is not necessary, you could implement your own error handling logic.
import { Inject } from '#nestjs/common';
import { LoggerService } from '../../logger/logger.service';
export function logErrorDecorator(bubble = false) {
const injectLogger = Inject(LoggerService);
return (target: any, propertyKey: string, propertyDescriptor: PropertyDescriptor) => {
injectLogger(target, 'logger'); // this is the same as using constructor(private readonly logger: LoggerService) in a class
//get original method
const originalMethod = propertyDescriptor.value;
//redefine descriptor value within own function block
propertyDescriptor.value = async function(...args: any[]) {
try {
return await originalMethod.apply(this, args);
} catch (error) {
const logger: LoggerService = this.logger;
logger.setContext(target.constructor.name);
logger.error(error.message, error.stack);
// rethrow error, so it can bubble up
if (bubble) {
throw error;
}
}
};
};
}
With this decorator you can simply add the logErrorDecorator() to your service class methods

Using Nestjs to poll on DB Changes

I am looking for an option to use nest as a back-end Gateway service -
The idea is to poll on DB changes ( and maybe later to move it to event driven ) - de facto no listener would be required here.
On change the Nest would update a 3rd pt API calls
What would be best practice here ?
Take a look here, I'm doing something similar to what you're after: https://github.com/nerdybeast/sith-api/blob/feature/redis-cache/src/modules/api/sobjects/trace-flag/TraceFlagPoller.ts
I created a class that "polls" a backend and emits an event when it detects a change in that backend. You could have other code that listens for this event which makes the call to your 3rd party api.
UPDATE:
As you stated, Nest does have a basic application context which skips the http service setup, here's how you can do that:
index.ts
import { NestFactory } from '#nestjs/core';
import { ApplicationModule } from './ApplicationModule';
import { DatabaseService } from './DatabaseService';
(async () => {
const app = await NestFactory.createApplicationContext(ApplicationModule);
const databaseService = app.get<DatabaseService>(DatabaseService);
await databaseService.poll();
})();
DatabaseService.ts
#Injectable()
export class DatabaseService {
private expectedResult: any;
public async poll() : Promise<void> {
const result = await getData();
if(result !== this.expectedResult) {
this.expectedResult = result;
await axios.post('https://some-url.com', result);
}
//Poll every 5 seconds or whatever
setTimeout(() => this.poll(), 5000);
}
}
This could be the solution if you had to poll the database instead of being able to subscribe to it. With this approach, when you start the app, it will poll forever, constantly updating your 3rd party api.
I would start the index.ts file with pm2 or forever so that you can have a graceful restart if your process crashes for some reason.
I would personally use typeORM subscribers like I have done many times for similar requirements. However I use an eventEmitter to not block the saving action. This is a snippet of what I usually do.
#Injectable()
export class EntityUpdate implements EntitySubscriberInterface {
constructor(
#InjectConnection() readonly connection: Connection,
#InjectEventManager() emitter: AppEvents<AbstractEntity>,
) {
connection.subscribers.push(this);
}
afterInsert(event: InsertEvent<AbstractEntity>): void {
this.emitter('entity', {
method: 'update',
entity,
});
}
}
Then I could listen to the event anywhere within my application and handle that status change of the entity

Resources