Skip to content

Commit 37cf337

Browse files
michaelmcneesclaude
andcommitted
fix: address release review findings — distributed CEL context, email limits, metrics
- MakeGlobalStepExecutor now loads failed-continued steps into CEL context, matching the sequential resumeExecution path so downstream expressions can reference error/output from continue_on_error steps - email/receive: cap limit param at 200 to prevent unbounded fetches - email_receive fetchMessages: remove redundant defer cmd.Close() that caused a double-close after the explicit close at end of function - metrics: add EmailTriggersSkippedTotal counter; increment in EmailTriggerPoller.startPoller when maxConnections limit is reached Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 9139594 commit 37cf337

4 files changed

Lines changed: 22 additions & 1 deletion

File tree

internal/connector/email_receive.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ func (c *EmailReceiveConnector) Execute(ctx context.Context, params map[string]a
4040
filter = v
4141
}
4242

43+
const maxEmailFetchLimit = 200
44+
4345
limit := 10
4446
switch v := params["limit"].(type) {
4547
case int:
@@ -51,6 +53,9 @@ func (c *EmailReceiveConnector) Execute(ctx context.Context, params map[string]a
5153
limit = int(v)
5254
}
5355
}
56+
if limit > maxEmailFetchLimit {
57+
limit = maxEmailFetchLimit
58+
}
5459

5560
markSeen := false
5661
if v, ok := params["mark_seen"].(bool); ok {
@@ -160,7 +165,6 @@ func buildSearchCriteria(filter string) *imap.SearchCriteria {
160165
// output map format expected by the connector.
161166
func fetchMessages(client *imapclient.Client, uidSet imap.UIDSet, opts *imap.FetchOptions) ([]map[string]any, error) {
162167
cmd := client.Fetch(uidSet, opts)
163-
defer func() { _ = cmd.Close() }()
164168

165169
var out []map[string]any
166170

internal/engine/engine.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,18 @@ func (e *Engine) MakeGlobalStepExecutor() StepExecutor {
725725
celCtx.Steps[name] = map[string]any{"output": output}
726726
}
727727

728+
// Load failed-but-continued steps for CEL context.
729+
failedContinuedSteps, err := e.loadFailedContinuedSteps(ctx, execID)
730+
if err != nil {
731+
return nil, fmt.Errorf("loading failed continued steps: %w", err)
732+
}
733+
for name, fcs := range failedContinuedSteps {
734+
celCtx.Steps[name] = map[string]any{
735+
"output": fcs.output,
736+
"error": fcs.errMsg,
737+
}
738+
}
739+
728740
// Load artifacts for CEL context.
729741
e.loadArtifactsIntoCELContext(ctx, execID, celCtx)
730742

internal/metrics/metrics.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ var (
151151
Name: "mantle_email_connection_errors_total",
152152
Help: "Total IMAP connection errors",
153153
}, []string{"workflow"})
154+
EmailTriggersSkippedTotal = promauto.NewCounter(prometheus.CounterOpts{
155+
Name: "mantle_email_triggers_skipped_total",
156+
Help: "Total email triggers skipped due to connection limit",
157+
})
154158
)
155159

156160
// Budget metrics.

internal/server/email_trigger.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ func (e *EmailTriggerPoller) startPoller(ctx context.Context, t TriggerRecord) {
121121
"trigger_id", t.ID,
122122
"workflow", t.WorkflowName,
123123
"max", e.maxConnections)
124+
metrics.EmailTriggersSkippedTotal.Inc()
124125
return
125126
}
126127

0 commit comments

Comments
 (0)