Skip to content

state: add new state package as a foundation for v2#83

Open
ecordell wants to merge 2 commits intoauthzed:mainfrom
ecordell:state
Open

state: add new state package as a foundation for v2#83
ecordell wants to merge 2 commits intoauthzed:mainfrom
ecordell:state

Conversation

@ecordell
Copy link
Contributor

@ecordell ecordell commented Feb 9, 2026

Description

There's lots of docs in the PR so I'll let those do most of the talking, but there were a few pain points I set out to address with this:

  1. It was too easy to forget to return from a handler, i.e. after calling requeue. This new state package relies on returning the next step to run (vs. directly calling the next step to run like in v1), so you can't forget. This is the primary low-level difference - building blocks are func(Context) Context instead of func(Context). There are some new things in the queue package to demonstrate this use too.
  2. I really disliked the fact that handlers needed string names in v1. The main reason was so that we could "find" the right handler if we needed to branch. The new state package addresses this by giving direct ways to compose handlers (examples will make it clear).

And in the back of my head I've always thought about these in terms of monadic structures. I don't think it's for everyone, but I took the time to write down what that actually means in the context of the state package and why it matters (library consumers don't need to worry about this, it's more philosophical)

Testing

This is not in practical use yet - there are unit tests and and I have follow on work that uses these new primitives, but wanted to keep the initial PR smaller.

Copy link
Contributor

@tstirrat15 tstirrat15 left a comment

Choose a reason for hiding this comment

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

See comments

func OnError(errorHandler, successHandler state.NewStep) state.NewStep {
return func(next state.Step) state.Step {
return state.StepFunc(func(ctx context.Context) state.Step {
if ctx.Err() != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

Or is the idea that we're using the error field on the context for this? Like where would this be set other than through cancellation?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is just for handling context cancellation, we do it a bunch so I wanted to make some helpers for it

Copy link
Contributor

Choose a reason for hiding this comment

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

General comment: I still don't understand how error handling works in this - how would an error result of (say) an API call be propagated up to an error-handling step? Are we sticking it on the context? That seems like it'd be a recipe for unhandled errors or error handling that behaves strangely when you introduce parallelism.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

#83 (comment)

yeah I addressed that here - I think I need a bit more docs / examples to explain it

@ecordell ecordell force-pushed the state branch 10 times, most recently from 4cf1007 to 15d7c2d Compare February 18, 2026 22:41
@ecordell
Copy link
Contributor Author

I've simplified and cleaned up a bit since I opened this, the new things to note are:

  • NewTerminalStepFunc helper - convenience for steps that run a side-effect and terminate
  • WithErrorHandler / Continue - error handler mechanism for cancelled contexts, replacing the original auto-recover behavior. Context cancellation now routes through Continue which checks for a registered error handler
  • When — sugar for Decision(pred, handler, Noop), one-branch conditional
  • Recover / PanicError - explicit opt-in panic recovery that routes the panic through WithErrorHandler rather than implicit recovery in all parallel branches
  • ParallelWith - helper to apply a uniform wrapper (e.g. Recover) to all parallel branches

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments