Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ interface IResultStateCount {
interface IErrorGroup {
errorMessage: string
location: string
message: string
count: number
avgRetries: number
maxRetries: number
Expand Down Expand Up @@ -69,7 +68,6 @@ const job: IJobDefinition = {
SELECT
COALESCE(r.error->>'errorMessage', '[no errorMessage]') AS "errorMessage",
COALESCE(r.error->>'location', '[no location]') AS location,
COALESCE(r.error->>'message', '[no message]') AS message,
count(*)::int AS count,
round(avg(r.retries), 1)::float AS "avgRetries",
max(r.retries)::int AS "maxRetries",
Expand All @@ -81,8 +79,7 @@ const job: IJobDefinition = {
WHERE r.state = 'error'
GROUP BY
r.error->>'errorMessage',
r.error->>'location',
r.error->>'message'
r.error->>'location'
ORDER BY count DESC
LIMIT 20
`,
Expand Down Expand Up @@ -125,7 +122,6 @@ const job: IJobDefinition = {
`• *${group.count}x* \`${group.errorMessage}\``,
` _Location:_ \`${group.location}\` | _retries avg/max:_ ${group.avgRetries}/${group.maxRetries}${group.platforms ? ` | _platforms:_ \`${group.platforms}\`` : ''}`,
` _Age:_ ${ageLabel}`,
` _Detail:_ ${group.message}`,
'',
)
}
Expand Down
43 changes: 31 additions & 12 deletions services/apps/data_sink_worker/src/service/dataSink.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,35 @@ import MemberService from './member.service'

/* eslint-disable @typescript-eslint/no-explicit-any */

/**
* Extracts the first app-code frame from an error's stack trace as the location.
* Uses process.cwd() (the service root) to match only this service's own source
* files, skipping node_modules and shared library frames.
*/
function extractLocationFromError(error: unknown): string {
const stack = (error as any)?.stack
if (!stack) return 'unknown'

const serviceDir = process.cwd()
for (const line of (stack as string).split('\n')) {
if (line.includes(serviceDir) && !line.includes('node_modules')) {
// Named frame: "at [async] FunctionName (file:line:col)"
const named = line.match(/at\s+(.+)\s+\((.+):(\d+):\d+\)/)
if (named) {
const file = named[2].replace(`${serviceDir}/`, '')
return `${file}:${named[3]} (${named[1].trim()})`
}
// Anonymous frame: "at file:line:col"
const anon = line.match(/at\s+\(?(.+):(\d+):\d+\)?/)
if (anon) {
return `${anon[1].replace(`${serviceDir}/`, '')}:${anon[2]}`
}
}
}

return 'unknown'
}
Comment thread
cursor[bot] marked this conversation as resolved.

export default class DataSinkService extends LoggerBase {
private readonly repo: DataSinkRepository

Expand All @@ -55,15 +84,12 @@ export default class DataSinkService extends LoggerBase {
private async triggerResultError(
resultInfo: IResultData,
resultExists: boolean,
location: string,
message: string,
error: any,
metadata?: Record<string, unknown>,
): Promise<void> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const errorData: any = {
location,
message,
location: extractLocationFromError(error),

metadata,

Expand Down Expand Up @@ -463,14 +489,7 @@ export default class DataSinkService extends LoggerBase {
if (!result.success) {
const resultInfo = single(results, (r) => r.id === resultId)

await this.triggerResultError(
resultInfo,
batchEntry.created,
'process-result',
'Error processing result.',
result.err,
result.metadata,
)
await this.triggerResultError(resultInfo, batchEntry.created, result.err, result.metadata)

errors++
} else {
Expand Down
Loading