Skip to content

Commit 98781c8

Browse files
committed
Devin fix
1 parent 4423aec commit 98781c8

File tree

1 file changed

+102
-97
lines changed

1 file changed

+102
-97
lines changed

apps/webapp/app/v3/services/alerts/errorAlertEvaluator.server.ts

Lines changed: 102 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -74,120 +74,125 @@ export class ErrorAlertEvaluator {
7474
}
7575

7676
const allEnvTypes = this.collectEnvironmentTypes(channels);
77-
const [project, environments] = await Promise.all([
78-
this._replica.project.findFirst({
79-
where: { id: projectId },
80-
select: { organizationId: true },
81-
}),
82-
this.resolveEnvironments(projectId, allEnvTypes),
83-
]);
84-
85-
if (!project) {
86-
logger.error("[ErrorAlertEvaluator] Project not found", { projectId });
87-
return;
88-
}
8977

90-
if (environments.length === 0) {
91-
logger.info("[ErrorAlertEvaluator] No matching environments found", { projectId });
92-
await this.selfChain(projectId, nextScheduledAt, minIntervalMs);
93-
return;
94-
}
78+
try {
79+
const [project, environments] = await Promise.all([
80+
this._replica.project.findFirst({
81+
where: { id: projectId },
82+
select: { organizationId: true },
83+
}),
84+
this.resolveEnvironments(projectId, allEnvTypes),
85+
]);
86+
87+
if (!project) {
88+
logger.error("[ErrorAlertEvaluator] Project not found", { projectId });
89+
return;
90+
}
9591

96-
const envIds = environments.map((e) => e.id);
97-
const envMap = new Map(environments.map((e) => [e.id, e]));
98-
const channelsByEnvId = this.buildChannelsByEnvId(channels, environments);
92+
if (environments.length === 0) {
93+
return;
94+
}
9995

100-
const activeErrors = await this.getActiveErrors(
101-
project.organizationId,
102-
projectId,
103-
envIds,
104-
scheduledAt
105-
);
96+
const envIds = environments.map((e) => e.id);
97+
const envMap = new Map(environments.map((e) => [e.id, e]));
98+
const channelsByEnvId = this.buildChannelsByEnvId(channels, environments);
10699

107-
if (activeErrors.length === 0) {
108-
await this.selfChain(projectId, nextScheduledAt, minIntervalMs);
109-
return;
110-
}
100+
const activeErrors = await this.getActiveErrors(
101+
project.organizationId,
102+
projectId,
103+
envIds,
104+
scheduledAt
105+
);
111106

112-
const states = await this.getErrorGroupStates(activeErrors);
113-
const stateMap = this.buildStateMap(states);
107+
if (activeErrors.length === 0) {
108+
return;
109+
}
114110

115-
const occurrenceCounts = await this.getOccurrenceCountsSince(
116-
project.organizationId,
117-
projectId,
118-
envIds,
119-
scheduledAt
120-
);
121-
const occurrenceMap = this.buildOccurrenceMap(occurrenceCounts);
111+
const states = await this.getErrorGroupStates(activeErrors);
112+
const stateMap = this.buildStateMap(states);
122113

123-
const alertableErrors: AlertableError[] = [];
114+
const occurrenceCounts = await this.getOccurrenceCountsSince(
115+
project.organizationId,
116+
projectId,
117+
envIds,
118+
scheduledAt
119+
);
120+
const occurrenceMap = this.buildOccurrenceMap(occurrenceCounts);
124121

125-
for (const error of activeErrors) {
126-
const key = `${error.environment_id}:${error.task_identifier}:${error.error_fingerprint}`;
127-
const state = stateMap.get(key);
128-
const env = envMap.get(error.environment_id);
129-
const firstSeenMs = Number(error.first_seen);
122+
const alertableErrors: AlertableError[] = [];
130123

131-
const classification = this.classifyError(error, state, firstSeenMs, scheduledAt, {
132-
occurrencesSince: occurrenceMap.get(key) ?? 0,
133-
windowMs,
134-
totalOccurrenceCount: error.occurrence_count,
135-
});
124+
for (const error of activeErrors) {
125+
const key = `${error.environment_id}:${error.task_identifier}:${error.error_fingerprint}`;
126+
const state = stateMap.get(key);
127+
const env = envMap.get(error.environment_id);
128+
const firstSeenMs = Number(error.first_seen);
136129

137-
if (classification) {
138-
alertableErrors.push({
139-
classification,
140-
error,
141-
environmentSlug: env?.slug ?? "",
142-
environmentName: env?.displayName ?? error.environment_id,
130+
const classification = this.classifyError(error, state, firstSeenMs, scheduledAt, {
131+
occurrencesSince: occurrenceMap.get(key) ?? 0,
132+
windowMs,
133+
totalOccurrenceCount: error.occurrence_count,
143134
});
135+
136+
if (classification) {
137+
alertableErrors.push({
138+
classification,
139+
error,
140+
environmentSlug: env?.slug ?? "",
141+
environmentName: env?.displayName ?? error.environment_id,
142+
});
143+
}
144144
}
145-
}
146145

147-
for (const alertable of alertableErrors) {
148-
const envChannels = channelsByEnvId.get(alertable.error.environment_id) ?? [];
149-
for (const channel of envChannels) {
150-
await alertsWorker.enqueue({
151-
id: `deliverErrorGroupAlert:${channel.id}:${alertable.error.error_fingerprint}:${scheduledAt}`,
152-
job: "v3.deliverErrorGroupAlert",
153-
payload: {
154-
channelId: channel.id,
155-
projectId,
156-
classification: alertable.classification,
157-
error: {
158-
fingerprint: alertable.error.error_fingerprint,
159-
environmentId: alertable.error.environment_id,
160-
environmentSlug: alertable.environmentSlug,
161-
environmentName: alertable.environmentName,
162-
taskIdentifier: alertable.error.task_identifier,
163-
errorType: alertable.error.error_type,
164-
errorMessage: alertable.error.error_message,
165-
sampleStackTrace: alertable.error.sample_stack_trace,
166-
firstSeen: alertable.error.first_seen,
167-
lastSeen: alertable.error.last_seen,
168-
occurrenceCount: alertable.error.occurrence_count,
146+
for (const alertable of alertableErrors) {
147+
const envChannels = channelsByEnvId.get(alertable.error.environment_id) ?? [];
148+
for (const channel of envChannels) {
149+
await alertsWorker.enqueue({
150+
id: `deliverErrorGroupAlert:${channel.id}:${alertable.error.error_fingerprint}:${scheduledAt}`,
151+
job: "v3.deliverErrorGroupAlert",
152+
payload: {
153+
channelId: channel.id,
154+
projectId,
155+
classification: alertable.classification,
156+
error: {
157+
fingerprint: alertable.error.error_fingerprint,
158+
environmentId: alertable.error.environment_id,
159+
environmentSlug: alertable.environmentSlug,
160+
environmentName: alertable.environmentName,
161+
taskIdentifier: alertable.error.task_identifier,
162+
errorType: alertable.error.error_type,
163+
errorMessage: alertable.error.error_message,
164+
sampleStackTrace: alertable.error.sample_stack_trace,
165+
firstSeen: alertable.error.first_seen,
166+
lastSeen: alertable.error.last_seen,
167+
occurrenceCount: alertable.error.occurrence_count,
168+
},
169169
},
170-
},
171-
});
170+
});
171+
}
172172
}
173-
}
174173

175-
const stateUpdates = alertableErrors.filter(
176-
(a) => a.classification === "regression" || a.classification === "unignored"
177-
);
178-
await this.updateErrorGroupStates(stateUpdates, stateMap);
179-
180-
logger.info("[ErrorAlertEvaluator] Evaluation complete", {
181-
projectId,
182-
activeErrors: activeErrors.length,
183-
alertableErrors: alertableErrors.length,
184-
deliveryJobsEnqueued: alertableErrors.reduce(
185-
(sum, a) => sum + (channelsByEnvId.get(a.error.environment_id)?.length ?? 0),
186-
0
187-
),
188-
});
174+
const stateUpdates = alertableErrors.filter(
175+
(a) => a.classification === "regression" || a.classification === "unignored"
176+
);
177+
await this.updateErrorGroupStates(stateUpdates, stateMap);
189178

190-
await this.selfChain(projectId, nextScheduledAt, minIntervalMs);
179+
logger.info("[ErrorAlertEvaluator] Evaluation complete", {
180+
projectId,
181+
activeErrors: activeErrors.length,
182+
alertableErrors: alertableErrors.length,
183+
deliveryJobsEnqueued: alertableErrors.reduce(
184+
(sum, a) => sum + (channelsByEnvId.get(a.error.environment_id)?.length ?? 0),
185+
0
186+
),
187+
});
188+
} catch (error) {
189+
logger.error("[ErrorAlertEvaluator] Evaluation failed, will retry on next cycle", {
190+
projectId,
191+
error,
192+
});
193+
} finally {
194+
await this.selfChain(projectId, nextScheduledAt, minIntervalMs);
195+
}
191196
}
192197

193198
private classifyError(

0 commit comments

Comments
 (0)