Skip to content

Commit a559a37

Browse files
committed
feat: step failed opcode
1 parent 38d86a0 commit a559a37

File tree

70 files changed

+1662
-640
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1662
-640
lines changed

go.mod

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require (
88
github.com/google/uuid v1.6.0
99
github.com/gosimple/slug v1.12.0
1010
github.com/gowebpki/jcs v1.0.0
11-
github.com/inngest/inngest v1.11.11-0.20250903154644-c3be9c4c8b45
11+
github.com/inngest/inngest v1.12.1
1212
github.com/oklog/ulid/v2 v2.1.1
1313
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58
1414
github.com/sashabaranov/go-openai v1.35.6
@@ -19,18 +19,29 @@ require (
1919
)
2020

2121
require (
22+
github.com/99designs/gqlgen v0.17.27 // indirect
2223
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
24+
github.com/agnivade/levenshtein v1.1.1 // indirect
2325
github.com/cespare/xxhash/v2 v2.3.0 // indirect
26+
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
2427
github.com/davecgh/go-spew v1.1.1 // indirect
28+
github.com/dmarkham/enumer v1.5.8 // indirect
2529
github.com/getsentry/sentry-go v0.27.0 // indirect
2630
github.com/gosimple/unidecode v1.0.1 // indirect
2731
github.com/hashicorp/errwrap v1.1.0 // indirect
2832
github.com/hashicorp/go-multierror v1.1.1 // indirect
2933
github.com/lmittmann/tint v1.1.0 // indirect
34+
github.com/pascaldekloe/name v1.0.1 // indirect
3035
github.com/pmezard/go-difflib v1.0.0 // indirect
36+
github.com/russross/blackfriday/v2 v2.1.0 // indirect
37+
github.com/urfave/cli/v2 v2.25.1 // indirect
38+
github.com/vektah/gqlparser/v2 v2.5.15 // indirect
39+
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
40+
golang.org/x/mod v0.25.0 // indirect
3141
golang.org/x/net v0.41.0 // indirect
32-
golang.org/x/sys v0.33.0 // indirect
42+
golang.org/x/sys v0.36.0 // indirect
3343
golang.org/x/text v0.26.0 // indirect
44+
golang.org/x/tools v0.33.0 // indirect
3445
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
3546
google.golang.org/grpc v1.73.0 // indirect
3647
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect

go.sum

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
1+
github.com/99designs/gqlgen v0.17.27 h1:XPsaZiWY1lL2qqVYtBt37GzkyX7bBiVvda7k1buC/Ao=
2+
github.com/99designs/gqlgen v0.17.27/go.mod h1:i4rEatMrzzu6RXaHydq1nmEPZkb3bKQsnxNRHS4DQB4=
13
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
24
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
5+
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
6+
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
7+
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
38
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
49
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
510
github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=
611
github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
12+
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
13+
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
714
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
815
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
916
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
17+
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
18+
github.com/dmarkham/enumer v1.5.8 h1:fIF11F9l5jyD++YYvxcSH5WgHfeaSGPaN/T4kOQ4qEM=
19+
github.com/dmarkham/enumer v1.5.8/go.mod h1:d10o8R3t/gROm2p3BXqTkMt2+HMuxEmWCXzorAruYak=
1020
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
1121
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
1222
github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
@@ -34,8 +44,10 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY
3444
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
3545
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
3646
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
37-
github.com/inngest/inngest v1.11.11-0.20250903154644-c3be9c4c8b45 h1:bk8rHGoa73umGpHKhIAFXgE7Bfh1pYv/6G8ZTv1FAxo=
38-
github.com/inngest/inngest v1.11.11-0.20250903154644-c3be9c4c8b45/go.mod h1:tt65lGtXioLxvpELpS1Y7/3ESrCaantUitJsqoQrVtM=
47+
github.com/inngest/inngest v1.11.14-0.20250926175522-7a60b676feb8 h1:z9l3Yk1nN6pDRmZjy2NQZ2jTV+jyHYOrs02+0kRxL6E=
48+
github.com/inngest/inngest v1.11.14-0.20250926175522-7a60b676feb8/go.mod h1:R5TKH7aKwziyiUOM7NxYqZxmsO78J/hCLT1frU5idzQ=
49+
github.com/inngest/inngest v1.12.1 h1:ftOopTJz0erpLXVCayPSl67Nuz6t1MZ1FTZsnSJx3q0=
50+
github.com/inngest/inngest v1.12.1/go.mod h1:R5TKH7aKwziyiUOM7NxYqZxmsO78J/hCLT1frU5idzQ=
3951
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
4052
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
4153
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -47,6 +59,8 @@ github.com/lmittmann/tint v1.1.0 h1:0hDmvuGv3U+Cep/jHpPxwjrCFjT6syam7iY7nTmA7ug=
4759
github.com/lmittmann/tint v1.1.0/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
4860
github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
4961
github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
62+
github.com/pascaldekloe/name v1.0.1 h1:9lnXOHeqeHHnWLbKfH6X98+4+ETVqFqxN09UXSjcMb0=
63+
github.com/pascaldekloe/name v1.0.1/go.mod h1:Z//MfYJnH4jVpQ9wkclwu2I2MkHmXTlT9wR5UZScttM=
5064
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
5165
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
5266
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
@@ -58,14 +72,22 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
5872
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5973
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
6074
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
75+
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
76+
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
6177
github.com/sashabaranov/go-openai v1.35.6 h1:oi0rwCvyxMxgFALDGnyqFTyCJm6n72OnEG3sybIFR0g=
6278
github.com/sashabaranov/go-openai v1.35.6/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
6379
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
6480
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
6581
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
6682
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
83+
github.com/urfave/cli/v2 v2.25.1 h1:zw8dSP7ghX0Gmm8vugrs6q9Ku0wzweqPyshy+syu9Gw=
84+
github.com/urfave/cli/v2 v2.25.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
85+
github.com/vektah/gqlparser/v2 v2.5.15 h1:fYdnU8roQniJziV5TDiFPm/Ff7pE8xbVSOJqbsdl88A=
86+
github.com/vektah/gqlparser/v2 v2.5.15/go.mod h1:WQQjFc+I1YIzoPvZBhUQX7waZgg3pMLi0r8KymvAE2w=
6787
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
6888
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
89+
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
90+
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
6991
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
7092
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
7193
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
@@ -78,15 +100,19 @@ go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFh
78100
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
79101
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
80102
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
103+
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
104+
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
81105
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
82106
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
83107
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
84108
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
85109
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
86-
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
87-
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
110+
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
111+
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
88112
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
89113
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
114+
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
115+
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
90116
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
91117
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
92118
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=

handler.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -844,13 +844,20 @@ func (h *handler) invoke(w http.ResponseWriter, r *http.Request) error {
844844
// For that reason, we check those values first.
845845
noRetry := sdkerrors.IsNoRetryError(err)
846846
retryAt := sdkerrors.GetRetryAtTime(err)
847+
847848
if len(ops) == 1 && ops[0].Op == enums.OpcodeStepError {
848849
// Now we've handled error types we can ignore step
849850
// errors safely.
850851
err = nil
851852
}
852853

853-
// Now that we've handled the OpcodeStepError, if we *still* ahve
854+
// Handle OpcodeStepFailed for permanent step failures
855+
if len(ops) == 1 && ops[0].Op == enums.OpcodeStepFailed {
856+
err = nil
857+
noRetry = true
858+
}
859+
860+
// Now that we've handled the OpcodeStepError, if we *still* have
854861
// a StepError kind returned from a function we must have an unhandled
855862
// step error. This is a NonRetryableError, as the most likely code is:
856863
//

internal/sdkrequest/request.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ type CallCtx struct {
2929
StepID string `json:"step_id"`
3030
Stack CallStack `json:"stack"`
3131
Attempt int `json:"attempt"`
32+
MaxAttempts *int `json:"max_attempts"`
3233
}
3334

3435
type CallStack struct {

step/run.go

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,22 +87,34 @@ func Run[T any](
8787
mutated := out.Result
8888
err = out.Error
8989
if err != nil {
90-
// If tihs is a StepFailure already, fail fast.
90+
// If this is a StepFailure already, fail fast.
9191
if errors.IsStepError(err) {
9292
mgr.SetErr(fmt.Errorf("unhandled step error: %s", err))
9393
panic(sdkrequest.ControlHijack{})
9494
}
9595

96+
isNoRetry := errors.IsNoRetryError(err)
97+
maxAttemptsReached := shouldUseStepFailed(mgr)
98+
9699
marshalled, _ := json.Marshal(mutated)
97100

98-
// Implement per-step errors.
101+
// Determine opcode based on retry eligibility
102+
opcode := enums.OpcodeStepError
103+
errorName := "Step error"
104+
105+
if isNoRetry || maxAttemptsReached {
106+
opcode = enums.OpcodeStepFailed
107+
errorName = "Step failed"
108+
}
109+
99110
mgr.SetErr(err)
111+
100112
mgr.AppendOp(ctx, sdkrequest.GeneratorOpcode{
101113
ID: hashedID,
102-
Op: enums.OpcodeStepError,
114+
Op: opcode,
103115
Name: id,
104116
Error: &sdkrequest.UserError{
105-
Name: "Step failed",
117+
Name: errorName,
106118
Message: err.Error(),
107119
Data: marshalled,
108120
},
@@ -180,3 +192,12 @@ func loadExistingStep[T any](
180192
val, _ := reflect.ValueOf(v).Elem().Interface().(T)
181193
return val, nil
182194
}
195+
196+
func shouldUseStepFailed(mgr sdkrequest.InvocationManager) bool {
197+
callCtx := mgr.Request().CallCtx
198+
if callCtx.MaxAttempts == nil {
199+
return false
200+
}
201+
202+
return callCtx.Attempt+1 >= *callCtx.MaxAttempts
203+
}

0 commit comments

Comments
 (0)