Repository navigation
refactor: replace optional task interfaces with TaskInfo, drop task wrappers - #2
Merged
Merged
Conversation
…rappers Optional task behavior was spread over five interfaces (TaskName, TaskSteps, TaskWithOptions, TaskWithInitError, TaskWithNotRun) discovered by type assertion, so every wrapper had to forward each of them by hand. Some layers missed one: decorating a futuretask with BuildTask(WithParent(...)) or instancetask.WithParent dropped TaskNotRun, leaving the future unresolved and its waiters blocked forever when the task's stage never ran. - Add TaskInfo (Name, Steps, Options, InitError, NotRun) returned by a single TaskWithInfo.TaskInfo() method, and GetTaskInfo. - Remove wrap.go (WrapTask, UnwrapTask, TaskWithWrapped, BaseOverloadedTask, BaseWrappedTask): use BuildTask(WithParent, WithName) to decorate and the WithHandler task option to customize step calls. - BuildTask merges its parent's TaskInfo (name fallback, options, init error, NotRun) and gains a WithNotRun option. Its computed state is stored atomically, as SetParent runs during the setup step. - instancetask.Build returns *instancetask.Task[T], which embeds the built task instead of forwarding its methods; adds instancetask.WithNotRun. - futuretask.New returns *futuretask.Task[T], built on instancetask with a WithNotRun callback instead of a hand-written forwarding wrapper. - ServiceName is removed: a Service may implement TaskWithInfo directly. - Regression test for the decorated futuretask never resolving. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CLyyJx24FhyAuthMeMuKPx
Task instance options were applied once, when the task was added, so options of a task only known after the "setup" step were ignored, like the ones from the task returned by an instancetask.Provider callback (WithCancelContext, WithStartStepManager). The task wrapper now keeps only the Manager.AddTask options, and computes the effective options from the task's current TaskInfo when they are used. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CLyyJx24FhyAuthMeMuKPx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Optional task behavior was spread over five interfaces (
TaskName,TaskSteps,TaskWithOptions,TaskWithInitError,TaskWithNotRun) discovered by type assertion. Every wrapper had to forward each one by hand, which led to several layers of wrapping (taskFuture→BaseOverloadedTask→instancetask.taskBuild→svcinit.taskBuild→ closures), and some layers missed one.This replaces them with a single extension point and removes the generic wrappers.
Changes
TaskInfo: a struct (Name,Steps,Options,InitError,NotRun) returned by one method,TaskWithInfo.TaskInfo(). The manager reads everything throughGetTaskInfo.Removed
wrap.go:WrapTask,UnwrapTask,TaskWithWrapped,BaseOverloadedTaskandBaseWrappedTaskare gone.BuildTask(WithParent(t), WithName(...)).WithHandleroption onAddTask.AddTask, so there is nothing to unwrap.BuildTaskis the only decorator: it merges its parent'sTaskInfo:NotRunis calledIt also gains a
WithNotRunoption. Its computed state is stored atomically, becauseSetParentruns during the setup step.instancetask.Buildreturns*instancetask.Task[T], which embeds the built task instead of forwarding its methods. Addsinstancetask.WithNotRun.futuretask.Newreturns*futuretask.Task[T]. It is nowinstancetask.Buildplus aWithNotRuncallback that resolves the future; the hand-written forwarding wrapper is gone.ServiceNameis removed: aServicecan implementTaskWithInfodirectly.Task options are computed when they are used, from the task's current
TaskInfo, instead of once inAddTask.README: new section documenting
TaskInfo.Bugs fixed
BuildTask(WithParent(...))orinstancetask.WithParentdropped its "not run" notification. If the task's stage never ran, the future was never resolved and anything waiting on itsValue()blocked forever.BuildTask(WithParent(x))droppedx's options. For example, wrappingSignalTaskorTimeoutTasklost theirWithCancelContext(true).BuildTaskignored its parent's init error. As a result, a task returned from aninstancetask.Providercallback with an init error was accepted silently.instancetask.Providercallback (WithCancelContext,WithStartStepManager) were ignored, because options were applied before the setup step created that task.Breaking changes
This is a breaking API change: the five optional interfaces,
ServiceNameand thewrap.goAPI are removed, and the return types ofinstancetask.Build,instancetask.Providerandfuturetask.Newchange.Test plan
go vet ./...go test -race -count=2 ./...TestNotRunDecorated(futuretask): a future decorated with one and two levels ofBuildTask(WithParent(...))resolves withErrTaskNotRunwhen an earlier stage's setup fails. Confirmed failing when the parentNotRunforwarding is removed.TestProviderTaskOptions(instancetask):WithCancelContextandWithStartStepManagerfrom a provided task take effect. Confirmed failing on the previous commit.BuildTaskdecorator tests cover info merging, parent options taking effect,WithHandler, callbacks receiving the decorated task, parent init errors, andNotRunordering.TestProviderInitErrorFromSetup: a provided task with an init error fails the setup step.🤖 Generated with Claude Code
https://claude.ai/code/session_01CLyyJx24FhyAuthMeMuKPx
Generated by Claude Code