Compare commits

...
Author SHA1 Message Date
sonarly-bot a042d14493 fix(server): harden Lambda calls against worker clock skew
https://sonarly.com/issue/38487?type=bug

Logic-function execution failed in production worker when AWS rejected a Lambda API call with `InvalidSignatureException` due to an outdated SigV4 timestamp. This caused background logic-function jobs to fail for affected executions.

Authored by Sonarly by autonomous analysis (run 43859).
2026-05-18 20:22:08 +00:00
3 changed files with 57 additions and 12 deletions
@@ -1149,6 +1149,15 @@ export class LambdaDriver implements LogicFunctionDriver {
};
}
private isInvalidSignatureException(error: unknown): boolean {
return (
isDefined(error) &&
typeof error === 'object' &&
'name' in error &&
error.name === 'InvalidSignatureException'
);
}
async execute({
flatLogicFunction,
flatApplication,
@@ -1236,11 +1245,6 @@ export class LambdaDriver implements LogicFunctionDriver {
status: LogicFunctionExecutionStatus.SUCCESS,
};
} catch (error) {
this.logger.error(
`Lambda invocation failed for function ${flatLogicFunction.id}: ${error instanceof Error ? error.message : String(error)}`,
error instanceof Error ? error.stack : undefined,
);
if (error instanceof ResourceNotFoundException) {
throw new LogicFunctionException(
`Function '${flatLogicFunction.id}' does not exist`,
@@ -1252,6 +1256,17 @@ export class LambdaDriver implements LogicFunctionDriver {
throw error;
}
if (this.isInvalidSignatureException(error)) {
this.logger.warn(
`Lambda invocation signature rejected for function ${flatLogicFunction.id}. This can indicate worker clock skew or event-loop stalls under load.`,
);
} else {
this.logger.error(
`Lambda invocation failed for function ${flatLogicFunction.id}: ${error instanceof Error ? error.message : String(error)}`,
error instanceof Error ? error.stack : undefined,
);
}
throw new LogicFunctionException(
`Lambda invocation failed for function '${flatLogicFunction.id}': ${error instanceof Error ? error.message : 'Unknown error'}`,
LogicFunctionExceptionCode.LOGIC_FUNCTION_EXECUTION_FAILED,
@@ -37,6 +37,10 @@ import { UsageResourceType } from 'src/engine/core-modules/usage/enums/usage-res
import { UsageUnit } from 'src/engine/core-modules/usage/enums/usage-unit.enum';
import { type UsageEvent } from 'src/engine/core-modules/usage/types/usage-event.type';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import {
LogicFunctionException,
LogicFunctionExceptionCode,
} from 'src/engine/metadata-modules/logic-function/logic-function.exception';
import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
import { SubscriptionChannel } from 'src/engine/subscriptions/enums/subscription-channel.enum';
import { SubscriptionService } from 'src/engine/subscriptions/subscription.service';
@@ -123,14 +127,25 @@ export class LogicFunctionExecutorService {
timeoutMs: flatLogicFunction.timeoutSeconds * 1_000,
});
} catch (error) {
this.logger.error(
const message =
`Logic function execution failed: ` +
`functionId=${logicFunctionId}, ` +
`workspaceId=${workspaceId}, ` +
`driver=${driver.constructor.name}: ` +
`${error instanceof Error ? error.message : String(error)}`,
error instanceof Error ? error.stack : undefined,
);
`functionId=${logicFunctionId}, ` +
`workspaceId=${workspaceId}, ` +
`driver=${driver.constructor.name}: ` +
`${error instanceof Error ? error.message : String(error)}`;
if (
error instanceof LogicFunctionException &&
error.code === LogicFunctionExceptionCode.LOGIC_FUNCTION_NOT_FOUND
) {
this.logger.warn(message);
} else {
this.logger.error(
message,
error instanceof Error ? error.stack : undefined,
);
}
throw error;
}
@@ -148,6 +148,10 @@ export class BullMQDriver
return;
}
this.logger.warn(
`Job ${job.id} with name ${job.name} failed on queue ${queueName} [workspace=${job.data?.workspaceId ?? 'n/a'}]: ${error.message}`,
);
void this.metricsService.incrementCounter({
key: MetricsKeys.JobFailed,
attributes: {
@@ -158,6 +162,17 @@ export class BullMQDriver
shouldStoreInCache: false,
});
});
this.workerMap[queueName].on('stalled', (jobId) => {
this.logger.warn(`Job ${jobId} stalled on queue ${queueName}`);
});
this.workerMap[queueName].on('error', (error) => {
this.logger.error(
`Worker error on queue ${queueName}: ${error.message}`,
error.stack,
);
});
}
async addCron<T>({