Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

API Convergence Matrix

Last Updated: 2026-01-08 Status: Active <- Back to Worker Crates Overview


Overview

This document provides a quick reference for the aligned APIs across Ruby, Python, TypeScript, and Rust worker implementations. All four languages share consistent patterns for handler execution, result creation, registry operations, and composition via mixins/traits.


Handler Signatures

LanguageBase ClassSignature
RubyTaskerCore::StepHandler::Basedef call(context)
PythonBaseStepHandlerdef call(self, context: StepContext) -> StepHandlerResult
TypeScriptStepHandlerasync call(context: StepContext): Promise<StepHandlerResult>
RustStepHandler traitasync fn call(&self, step_data: &TaskSequenceStep) -> StepExecutionResult

Composition Pattern

All languages use composition via mixins/traits rather than inheritance hierarchies.

Handler Composition

LanguageBaseMixin SyntaxExample
RubyStepHandler::Baseinclude Mixins::APIclass Handler < Base; include Mixins::API
PythonStepHandlerMultiple inheritanceclass Handler(StepHandler, APIMixin)
TypeScriptStepHandlerapplyAPI(this)Mixin functions applied in constructor
Rustimpl StepHandlerimpl APICapableMultiple trait implementations

Available Mixins/Traits

CapabilityRubyPythonTypeScriptRust
APIMixins::APIAPIMixinapplyAPI()APICapable
DecisionMixins::DecisionDecisionMixinapplyDecision()DecisionCapable
BatchableMixins::BatchableBatchableMixinBatchableHandlerBatchableCapable

StepContext Fields

The StepContext provides unified access to step execution data across Ruby, Python, and TypeScript.

FieldTypeDescription
task_uuidStringUnique task identifier (UUID v7)
step_uuidStringUnique step identifier (UUID v7)
input_dataDict/HashInput data for the step from workflow_step.inputs
step_inputsDict/HashAlias for input_data
step_configDict/HashHandler configuration from step_definition.handler.initialization
dependency_resultsWrapperResults from parent steps (DependencyResultsWrapper)
retry_countIntegerCurrent retry attempt (from workflow_step.attempts)
max_retriesIntegerMaximum retry attempts (from workflow_step.max_attempts)

Convenience Methods

MethodDescription
get_task_field(name)Get field from task context
get_dependency_result(step_name)Get result from a parent step

Ruby-Specific Accessors

PropertyTypeDescription
taskTaskWrapperFull task wrapper with context and metadata
workflow_stepWorkflowStepWrapperWorkflow step with execution state
step_definitionStepDefinitionWrapperStep definition from task template

Result Factories

Success Results

LanguageMethodExample
Rubysuccess(result:, metadata:)success(result: { id: 123 }, metadata: { ms: 50 })
Pythonself.success(result, metadata)self.success({"id": 123}, {"ms": 50})
RustStepExecutionResult::success(...)StepExecutionResult::success(result, metadata)

Failure Results

LanguageMethodKey Parameters
Rubyfailure(message:, error_type:, error_code:, retryable:, metadata:)keyword arguments
Pythonself.failure(message, error_type, error_code, retryable, metadata)positional/keyword
RustStepExecutionResult::failure(...)structured fields

Result Fields

FieldRubyPythonRustDescription
successboolboolboolWhether step succeeded
resultHashDictHashMapResult data
metadataHashDictHashMapAdditional context
error_messageStringstrStringHuman-readable error
error_typeStringstrStringError classification
error_codeString (optional)str (optional)String (optional)Application error code
retryableboolboolboolWhether to retry

Standard error_type Values

Use these standard values for consistent error classification:

ValueDescriptionRetry Behavior
PermanentErrorNon-recoverable failureNever retry
RetryableErrorTemporary failureWill retry
ValidationErrorInput validation failedNo retry
TimeoutErrorOperation timed outMay retry
UnexpectedErrorUnexpected handler errorMay retry

Registry API

OperationRubyPythonRust
Registerregister(name, klass)register(name, klass)register_handler(name, handler)
Checkis_registered(name)is_registered(name)is_registered(name)
Resolveresolve(name)resolve(name)get_handler(name)
Listlist_handlerslist_handlers()list_handlers()

Note: Ruby also provides original method names (register_handler, handler_available?, resolve_handler, registered_handlers) as the primary API with the above as cross-language aliases.


Resolver Chain API

Handler resolution uses a chain-of-responsibility pattern to convert callable addresses into executable handlers.

StepHandlerResolver Interface

MethodRubyPythonTypeScriptRust
Get Namenameresolver_name()resolverName()resolver_name(&self)
Get Priorityprioritypriority()priority()priority(&self)
Can Resolve?can_resolve?(definition, config)can_resolve(definition)canResolve(definition)can_resolve(&self, definition)
Resolveresolve(definition, config)resolve(definition, context)resolve(definition, context)resolve(&self, definition, context)

ResolverChain Operations

OperationRubyPythonTypeScriptRust
CreateResolverChain.newResolverChain()new ResolverChain()ResolverChain::new()
Registerregister(resolver)register(resolver)register(resolver)register(resolver)
Resolveresolve(definition, context)resolve(definition, context)resolve(definition, context)resolve(definition, context)
Can Resolve?can_resolve?(definition)can_resolve(definition)canResolve(definition)can_resolve(definition)
Listresolversresolversresolversresolvers()

Built-in Resolvers

ResolverPriorityFunctionRustRubyPythonTypeScript
ExplicitMappingResolver10Hash lookup of registered handlers
ClassConstantResolver100Runtime class lookup (Ruby)--
ClassLookupResolver100Runtime class lookup (Python/TS)-

Note: Class lookup resolvers are not available in Rust due to lack of runtime reflection. Rust handlers must use ExplicitMappingResolver. Ruby uses ClassConstantResolver (Ruby terminology); Python and TypeScript use ClassLookupResolver (same functionality, language-appropriate naming).

HandlerDefinition Fields

FieldTypeDescriptionRequired
callableStringHandler address (name or class path)Yes
methodStringEntry point method (default: "call")No
resolverStringResolution hint to bypass chainNo
initializationDict/HashHandler configurationNo

Method Dispatch

Multi-method handlers expose multiple entry points through the method field:

LanguageDefault MethodDynamic Dispatch
Rubycallhandler.public_send(method, context)
Pythoncallgetattr(handler, method)(context)
TypeScriptcallhandler[method](context)
Rustcallhandler.invoke_method(method, step)

Creating Multi-Method Handlers:

LanguageSignature
RubyDefine additional methods alongside call
PythonDefine additional methods alongside call
TypeScriptDefine additional async methods alongside call
RustImplement invoke_method to dispatch to internal methods

See Handler Resolution Guide for complete documentation.


Specialized Handlers

API Handler

OperationRubyPythonTypeScript
GETget(path, params: {}, headers: {})self.get(path, params={}, headers={})this.get(path, params?, headers?)
POSTpost(path, data: {}, headers: {})self.post(path, data={}, headers={})this.post(path, data?, headers?)
PUTput(path, data: {}, headers: {})self.put(path, data={}, headers={})this.put(path, data?, headers?)
DELETEdelete(path, params: {}, headers: {})self.delete(path, params={}, headers={})this.delete(path, params?, headers?)

Decision Handler

LanguageSimple APIResult Fields
Rubydecision_success(steps:, routing_context:)decision_point_outcome: { type, step_names }
Pythondecision_success(steps, routing_context)decision_point_outcome: { type, step_names }
TypeScriptdecisionSuccess(steps, routingContext?)decision_point_outcome: { type, step_names }
Rustdecision_success(step_uuid, step_names, ...)Pattern-based

Decision Helper Methods (Cross-Language):

  • decision_success(steps, routing_context) - Create dynamic steps
  • skip_branches(reason, routing_context) - Skip all conditional branches
  • decision_failure(message, error_type) - Decision could not be made

Batchable Handler

OperationRubyPythonTypeScript
Get Contextget_batch_context(context)get_batch_context(context)getBatchContext(context)
Complete Batchbatch_worker_complete(processed_count:, result_data:)batch_worker_complete(processed_count, result_data)batchWorkerComplete(processedCount, resultData)
Handle No-Ophandle_no_op_worker(batch_ctx)handle_no_op_worker(batch_ctx)handleNoOpWorker(batchCtx)

Standard Batch Result Fields:

  • processed_count / items_processed
  • items_succeeded / items_failed
  • start_cursor, end_cursor, batch_size, last_cursor

Cursor Indexing:

  • All languages use 0-indexed cursors (start at 0, not 1)
  • Ruby was updated from 1-indexed to 0-indexed for consistency

Checkpoint Yielding

Checkpoint yielding enables batch workers to persist progress and yield control for re-dispatch.

OperationRubyPythonTypeScript
Checkpointcheckpoint_yield(cursor:, items_processed:, accumulated_results:)checkpoint_yield(cursor, items_processed, accumulated_results)checkpointYield({ cursor, itemsProcessed, accumulatedResults })

BatchWorkerContext Checkpoint Accessors:

AccessorRubyPythonTypeScript
Cursorcheckpoint_cursorcheckpoint_cursorcheckpointCursor
Accumulated Resultsaccumulated_resultsaccumulated_resultsaccumulatedResults
Has Checkpoint?has_checkpoint?has_checkpoint()hasCheckpoint()
Items Processedcheckpoint_items_processedcheckpoint_items_processedcheckpointItemsProcessed

FFI Contract:

FunctionDescription
checkpoint_yield_step_event(event_id, data)Persist checkpoint and re-dispatch step

Key Invariants:

  • Progress is atomically saved before re-dispatch
  • Step remains InProgress during checkpoint yield cycle
  • Only Success/Failure trigger state transitions

See Batch Processing Guide - Checkpoint Yielding for full documentation.


Domain Events

Publisher Contract

LanguageBase ClassKey Method
RubyTaskerCore::DomainEvents::BasePublisherpublish(ctx)
PythonBasePublisherpublish(ctx)
TypeScriptBasePublisherpublish(ctx)
RustStepEventPublisher traitpublish(ctx)

Publisher Lifecycle Hooks

All languages support publisher lifecycle hooks for instrumentation:

HookRubyPythonTypeScriptDescription
Before Publishbefore_publish(ctx)before_publish(ctx)beforePublish(ctx)Called before publishing
After Publishafter_publish(ctx, result)after_publish(ctx, result)afterPublish(ctx, result)Called after successful publish
On Erroron_publish_error(ctx, error)on_publish_error(ctx, error)onPublishError(ctx, error)Called on publish failure
Metadataadditional_metadata(ctx)additional_metadata(ctx)additionalMetadata(ctx)Inject custom metadata

StepEventContext Fields

FieldDescription
task_uuidTask identifier
step_uuidStep identifier
step_nameHandler/step name
namespaceTask namespace
correlation_idTracing correlation ID
resultStep execution result
metadataAdditional metadata

Subscriber Contract

LanguageBase ClassKey Methods
RubyTaskerCore::DomainEvents::BaseSubscribersubscribes_to, handle(event)
PythonBaseSubscribersubscribes_to(), handle(event)
TypeScriptBaseSubscribersubscribesTo(), handle(event)
RustEventHandler closuresN/A

Subscriber Lifecycle Hooks

All languages support subscriber lifecycle hooks:

HookRubyPythonTypeScriptDescription
Before Handlebefore_handle(event)before_handle(event)beforeHandle(event)Called before handling
After Handleafter_handle(event, result)after_handle(event, result)afterHandle(event, result)Called after handling
On Erroron_handle_error(event, error)on_handle_error(event, error)onHandleError(event, error)Called on handler failure

Registries

LanguagePublisher RegistrySubscriber Registry
RubyPublisherRegistry.instanceSubscriberRegistry.instance
PythonPublisherRegistry.instance()SubscriberRegistry.instance()
TypeScriptPublisherRegistry.getInstance()SubscriberRegistry.getInstance()

Migration Summary

Ruby

BeforeAfter
def call(task, sequence, step)def call(context)
class Handler < APIclass Handler < Base; include Mixins::API
task.context['field']context.get_task_field('field')
sequence.get_results('step')context.get_dependency_result('step')
1-indexed cursors0-indexed cursors

Python

BeforeAfter
def handle(self, task, sequence, step)def call(self, context)
class Handler(APIHandler)class Handler(StepHandler, APIMixin)
N/Aself.success(result, metadata)
N/APublisher/Subscriber lifecycle hooks

TypeScript

BeforeAfter
class Handler extends APIHandlerclass Handler extends StepHandler implements APICapable
No domain eventsComplete domain events module
N/APublisher/Subscriber lifecycle hooks
N/AapplyAPI(this), applyDecision(this) mixins

Rust

BeforeAfter
(already aligned)(already aligned)
N/AAPICapable, DecisionCapable, BatchableCapable traits

See Also