Skip to content

A durable workflow engine for Ruby on Rails that provides reliable state management, error recovery, and workflow orchestration through ActiveJob

License

Notifications You must be signed in to change notification settings

radioactive-labs/chrono_forge

Repository files navigation

ChronoForge

ChronoForge is a Ruby gem that provides a robust framework for building durable, distributed workflows in Ruby on Rails applications. It offers a reliable way to handle long-running processes, state management, and error recovery.

Features

  • Durable Execution: Automatically tracks and recovers from failures during workflow execution
  • State Management: Built-in workflow state tracking with support for custom contexts
  • Concurrency Control: Advanced locking mechanisms to prevent concurrent execution of the same workflow
  • Error Handling: Comprehensive error tracking and retry strategies
  • Execution Logging: Detailed logging of workflow execution steps and errors
  • Wait States: Support for time-based waits and condition-based waiting
  • Database-Backed: All workflow state is persisted to the database for durability
  • ActiveJob Integration: Seamlessly works with any ActiveJob backend

Installation

Add this line to your application's Gemfile:

gem 'chrono_forge'

Then execute:

$ bundle install

Or install it directly:

$ gem install chrono_forge

After installation, run the generator to create the necessary database migrations:

$ rails generate chrono_forge:install
$ rails db:migrate

Usage

Basic Workflow Example

Here's a complete example of a durable order processing workflow:

class OrderProcessingWorkflow < ApplicationJob
  include ChronoForge::Executor

  def perform
    # Context can be used to pass and store data between executions
    context["order_id"] = SecureRandom.hex

    # Wait until payment is confirmed
    wait_until :payment_confirmed?

    # Wait for potential fraud check
    wait 1.minute, :fraud_check_delay

    # Durably execute order processing
    durably_execute :process_order

    # Final steps
    complete_order
  end

  private

  def payment_confirmed?
    PaymentService.confirmed?(context["order_id"])
  end

  def process_order
    context["processed_at"] = Time.current.iso8601
    OrderProcessor.process(context["order_id"])
  end

  def complete_order
    context["completed_at"] = Time.current.iso8601
    OrderCompletionService.complete(context["order_id"])
  end
end

Workflow Features

Durable Execution

The durably_execute method ensures operations are executed exactly once:

# Execute a method
durably_execute(:process_payment, max_attempts: 3)

# Or with a block
durably_execute -> (ctx) {
  Payment.process(ctx[:payment_id])
}

Wait States

ChronoForge supports both time-based and condition-based waits:

# Wait for a specific duration
wait 1.hour, :cooling_period

# Wait until a condition is met
wait_until :payment_processed, 
  timeout: 1.hour,
  check_interval: 5.minutes

Workflow Context

ChronoForge provides a persistent context that survives job restarts:

# Set context values
context[:user_name] = "John Doe"
context[:status] = "processing"

# Read context values
user_name = context[:user_name]

Error Handling

ChronoForge automatically tracks errors and provides retry capabilities:

class MyWorkflow < ApplicationJob
  include ChronoForge::Executor

  private

  def should_retry?(error, attempt_count)
    case error
    when NetworkError
      attempt_count < 5
    when ValidationError
      false  # Don't retry validation errors
    else
      attempt_count < 3
    end
  end
end

Testing

ChronoForge is designed to be easily testable using ChaoticJob, a testing framework that makes it simple to test complex job workflows. Here's how to set up your test environment:

  1. Add ChaoticJob to your Gemfile's test group:
group :test do
  gem 'chaotic_job'
end
  1. Set up your test helper:
# test_helper.rb
require 'chrono_forge'
require 'minitest/autorun'
require 'chaotic_job'

Example test:

class WorkflowTest < ActiveJob::TestCase
  include ChaoticJob::Helpers

  def test_workflow_completion
    # Enqueue the job
    OrderProcessingWorkflow.perform_later("order_123")
    
    # Perform all enqueued jobs
    perform_all_jobs
    
    # Assert workflow completed successfully
    workflow = ChronoForge::Workflow.last
    assert workflow.completed?
    
    # Check workflow context
    assert workflow.context["processed_at"].present?
    assert workflow.context["completed_at"].present?
  end
end

ChaoticJob provides several helpful methods for testing workflows:

  • perform_all_jobs: Processes all enqueued jobs, including those enqueued during job execution

For testing with specific job processing libraries like Sidekiq or Delayed Job, you can still use their respective testing modes, but ChaoticJob is recommended for testing ChronoForge workflows as it better handles the complexities of nested job scheduling and wait states.

Database Schema

ChronoForge creates three main tables:

  1. chrono_forge_workflows: Stores workflow state and context
  2. chrono_forge_execution_logs: Tracks individual execution steps
  3. chrono_forge_error_logs: Records detailed error information

Development

After checking out the repo, run:

$ bin/setup                 # Install dependencies
$ bundle exec rake test     # Run the tests
$ bin/appraise              # Run the full suite of appraisals
$ bin/console               # Start an interactive console

The test suite uses SQLite by default and includes:

  • Unit tests for core functionality
  • Integration tests with ActiveJob
  • Example workflow implementations

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin feature/my-new-feature)
  5. Create a new Pull Request

Please include tests for any new features or bug fixes.

License

This gem is available as open source under the terms of the MIT License.

About

A durable workflow engine for Ruby on Rails that provides reliable state management, error recovery, and workflow orchestration through ActiveJob

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published