Fixing not-locally-reproducable unhandledRejection with rethrow

30 Views Asked by At

The nodejs 18 server crashes because of an unhandledRejection sometimes, pointing to the code below. It only happens on prod and is not redproducable locally. The error is getting catched, and because it doesn't happen all the time it's hard to find the reason. I am already rethrowing the error, but it doesn't help.

    private async verifySomething(req: Request, res: Response): Promise<void> {
        try {
            const { type } = req.body;

            assert(typeof type === "string");
            const something = await this.findSomethingByType(type);
            NotFoundError.assert(something);

            await this.somethingPolicy.checkSomething(something).catch(Promise.reject(error)); // <-- rethrow here
            return await this.doStuff(something, req);            
        } catch (error) {
            await this.doOtherStuff(req, res, error);
        }
    }


    public async checkSomething(something: ISomething | null): Promise<void> {
        const [failedAttempts, policies] = await Promise.all([
            this.getFailedAttemptCount(something),
            this.getPolicies(something)
        ]);

        this.checkRules(something, failedAttempts, policies ? policies : undefined);
        this.doSomething(something),
    }

    private checkRules(something: ISomething | null, failedAttempts?: number, policies?: IPolicies): void {
        this.invokeRules(this.getRules(), something, failedAttempts, policies);
    }

    private getRules(): RuleCallbackType[] {
        // if policy fails it throws an error - all synchronous
        return [
            this.somethingNotFound,
            this.hasTriedToManyTimes,
            this.isSpecialSomething,
            this.hasWrongProperties,
            ...this.getAdditionalRules()
        ];
    }

    private somethingNotFound(something: ISomething | null): asserts somethingis ISomething {
        // the other checks are similar to this with void return type
        if (something === null) {
            throw new SpecialError();
        }
    }

    private hasTriedToManyTimes(something: ISomething | null, failedAttempts?: number): void {
        if (Number(failedAttempts) > Policy.MAX_SUCCESSIVE_FAILURES) {
            this.logFailedAttempts(something.type); // async but we don't wait for it
            throw new SpecialError(); // <-- this is the error causing the crash
        }
    }

    private invokeRules(rules: RuleCallbackType[], something: ISomething, failedAttempts?: number,
        policies?: IPolicies
    ): void {
        for (const rule of rules) {
            rule.call(this, something, failedAttempts, policies);
        }
    }

exiting after unhandledRejection, SpecialError SpecialError Error: SpecialError
    at SomethingPolicy.hasTriedToManyTimes 
    at SomethingPolicy.invokeRules 
    at SomethingPolicy.checkRules
    at SomethingPolicy.checkSomething
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at /xyz/BasicSomethingPolicy.ts:25:13 stack=Error: SpecialError 
    at SomethingPolicy.hasTriedToManyTimes 
    at SomethingPolicy.invokeRules 
    at SomethingPolicy.checkRules
    at SomethingPolicy.checkSomething
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at /xyz/BasicSomethingPolicy.ts:25:13 stack=Error: SpecialError 

I'd like to know the reason behind this, before I try some more workarounds. Could .call(...) be causing this problem?

0

There are 0 best solutions below