Skip to content

chore: drop external payload not found errors#4308

Open
grutt wants to merge 2 commits into
mainfrom
chore--drop-external-payload-not-found-errors
Open

chore: drop external payload not found errors#4308
grutt wants to merge 2 commits into
mainfrom
chore--drop-external-payload-not-found-errors

Conversation

@grutt

@grutt grutt commented Jun 29, 2026

Copy link
Copy Markdown
Member

Description

Adds a terminal external payload not found error and teaches RabbitMQ pre-ack handling to drop those messages instead of retrying indefinitely. This prevents missing S3 offloaded payload index files from generating noisy retry storms, while keeping other S3 failures retryable.

The permanent drop log is enriched with structured fields like permanent_pre_ack_reason=external_payload_not_found, external_payload_kind, and external_payload_key for filtering and alerting.

Fixes #

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Test changes (add, refactor, improve or change a test)

What's Changed

  • Add a shared ErrExternalPayloadNotFound typed error for terminal external payload misses.
  • Treat external payload not found errors as permanent RabbitMQ pre-ack failures.
  • Add structured permanent drop reason fields to RabbitMQ logs.
  • Map S3 NoSuchKey index file fetch errors to the terminal payload error.
  • Add focused tests for permanent pre-ack classification and S3 index file error classification.

Checklist

Changes have been:

  • Tested (unit, integration, or manually with steps specified)
  • Linted and formatted
  • Documented (where applicable)
  • Added to CHANGELOG (where applicable) -- see Keep a Changelog

Testing

  • go test ./internal/msgqueue/rabbitmq -run 'TestIsPermanentPreAckError' -count=1
  • go test ./pkg/repository -run '^$' -count=1
  • GOWORK=<temp local workspace> go test github.com/hatchet-dev/hatchet-cloud/internal/repository -run 'Test(FetchWithFallback|IndexFileFetchError)' -count=1

🤖 AI Disclosure
  • I acknowledge that an LLM was used in the creation of this Pull Request, in accordance with Hatchet's AI_POLICY.md.

  • Details: Cursor agent was used to inspect the retry/error paths, implement the targeted code changes, add focused tests, and run validation commands.

Copilot AI review requested due to automatic review settings June 29, 2026 20:27
@vercel

vercel Bot commented Jun 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hatchet-docs Ready Ready Preview, Comment Jun 30, 2026 5:07pm

Request Review

@github-actions github-actions Bot added the engine Related to the core Hatchet engine label Jun 29, 2026
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Benchmark results

goos: linux
goarch: amd64
pkg: github.com/hatchet-dev/hatchet/internal/msgqueue/rabbitmq
cpu: AMD Ryzen 9 7950X3D 16-Core Processor          
                              │ /tmp/old.txt │            /tmp/new.txt            │
                              │    sec/op    │    sec/op     vs base              │
CompressPayloads_1x10KiB-8       78.87µ ± 2%   77.79µ ±  2%       ~ (p=0.065 n=6)
CompressPayloads_10x10KiB-8      894.5µ ± 3%   898.9µ ±  4%       ~ (p=0.699 n=6)
CompressPayloads_10x100KiB-8     10.59m ± 1%   10.43m ±  1%  -1.53% (p=0.009 n=6)
CompressPayloads_Concurrent-8    76.71µ ± 8%   83.19µ ± 18%       ~ (p=0.310 n=6)
geomean                          489.3µ        496.3µ        +1.43%

                              │ /tmp/old.txt │            /tmp/new.txt            │
                              │     B/op     │     B/op      vs base              │
CompressPayloads_1x10KiB-8      11.01Ki ± 1%   10.90Ki ± 1%       ~ (p=0.106 n=6)
CompressPayloads_10x10KiB-8     108.3Ki ± 1%   108.9Ki ± 1%       ~ (p=0.368 n=6)
CompressPayloads_10x100KiB-8    2.920Mi ± 0%   2.920Mi ± 0%       ~ (p=0.626 n=6)
CompressPayloads_Concurrent-8   54.28Ki ± 0%   54.34Ki ± 1%       ~ (p=0.818 n=6)
geomean                         118.0Ki        117.8Ki       -0.10%

                              │ /tmp/old.txt │            /tmp/new.txt            │
                              │  allocs/op   │ allocs/op   vs base                │
CompressPayloads_1x10KiB-8        5.000 ± 0%   5.000 ± 0%       ~ (p=1.000 n=6) ¹
CompressPayloads_10x10KiB-8       32.00 ± 0%   32.00 ± 0%       ~ (p=1.000 n=6) ¹
CompressPayloads_10x100KiB-8      63.00 ± 0%   63.00 ± 0%       ~ (p=1.000 n=6) ¹
CompressPayloads_Concurrent-8     17.00 ± 0%   17.00 ± 0%       ~ (p=1.000 n=6) ¹
geomean                           20.35        20.35       +0.00%
¹ all samples are equal

pkg: github.com/hatchet-dev/hatchet/pkg/scheduling/v1
              │ /tmp/old.txt │         /tmp/new.txt         │
              │    sec/op    │   sec/op     vs base         │
RateLimiter-8    61.31µ ± 8%   57.34µ ± 9%  ~ (p=0.132 n=6)

              │ /tmp/old.txt │            /tmp/new.txt            │
              │     B/op     │     B/op      vs base              │
RateLimiter-8   137.7Ki ± 0%   137.7Ki ± 0%  -0.01% (p=0.048 n=6)

              │ /tmp/old.txt │          /tmp/new.txt          │
              │  allocs/op   │  allocs/op   vs base           │
RateLimiter-8    1.022k ± 0%   1.022k ± 0%  ~ (p=1.000 n=6) ¹
¹ all samples are equal

Compared against main (bd76868)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to prevent RabbitMQ pre-ack retry storms by treating “external payload not found” as a terminal (permanent) pre-ack failure and enriching drop logs with structured context for alerting/filtering.

Changes:

  • Introduces a shared ErrExternalPayloadNotFound sentinel and ExternalPayloadNotFoundError wrapper in the repository layer.
  • Extends RabbitMQ pre-ack error classification to treat ErrExternalPayloadNotFound as permanent and logs permanent_pre_ack_reason plus external payload metadata.
  • Adds unit coverage for the new permanent pre-ack classification.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
pkg/repository/payloadstore.go Adds a typed/sentinel error to represent terminal external payload misses.
internal/msgqueue/rabbitmq/rabbitmq.go Classifies external-payload-not-found as a permanent pre-ack failure and enriches drop logs with structured fields.
internal/msgqueue/rabbitmq/permanent_preack_test.go Adds test coverage for the external-payload-not-found permanent classification.

Comment thread internal/msgqueue/rabbitmq/rabbitmq.go Outdated
Comment on lines 926 to 928
if errors.Is(err, repository.ErrExternalPayloadNotFound) {
return "external_payload_not_found"
}
Comment thread internal/msgqueue/rabbitmq/rabbitmq.go Outdated
return permanentPreAckErrorReason(err) != ""
}

func permanentPreAckErrorReason(err error) string {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this can work at the msgqueue layer, because messages are buffered (on both the pub and sub side). So consumers will need to shed these messages.

If we wanted to only nack part of the batch we'd need need to support individual acks for each message in the buffer, which we don't currently. But even if we did this, there's no way of getting around the pub buffer (which is why the pub buffer should be used sparingly)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

engine Related to the core Hatchet engine

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants