ruby-concurrency / ruby-concurrency/concurrent-ruby

Backtrace propagation into the executor

Open
#810 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement looking-for-contributor
Dominant language
Ruby
Stars
5.8k
Forks
420
Avg merge
20h 45m
Merged PRs (30d)
4

Description

When an error occurs within some code running inside concurrent-ruby executor, it ends up with something like this, while loosing the info about the true origin of the code:

concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/behaviour/abstract.rb:25:in `pass'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/behaviour/awaits.rb:15:in `on_envelope'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/behaviour/abstract.rb:25:in `pass'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/behaviour/sets_results.rb:14:in `on_envelope'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/behaviour/abstract.rb:25:in `pass'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/behaviour/buffer.rb:38:in `process_envelope'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/behaviour/buffer.rb:31:in `process_envelopes?'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/behaviour/buffer.rb:20:in `on_envelope'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/behaviour/abstract.rb:25:in `pass'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/behaviour/termination.rb:55:in `on_envelope'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/behaviour/abstract.rb:25:in `pass'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/behaviour/removes_child.rb:10:in `on_envelope'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/behaviour/abstract.rb:25:in `pass'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/behaviour/sets_results.rb:14:in `on_envelope'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/core.rb:162:in `process_envelope'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/core.rb:96:in `block in on_envelope'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/core.rb:119:in `block (2 levels) in schedule_execution'
concurrent-ruby-1.1.5/lib/concurrent/synchronization/mutex_lockable_object.rb:41:in `block in synchronize'
concurrent-ruby-1.1.5/lib/concurrent/synchronization/mutex_lockable_object.rb:41:in `synchronize'
concurrent-ruby-1.1.5/lib/concurrent/synchronization/mutex_lockable_object.rb:41:in `synchronize'
concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/core.rb:116:in `block in schedule_execution'
concurrent-ruby-1.1.5/lib/concurrent/executor/serialized_execution.rb:18:in `call'
concurrent-ruby-1.1.5/lib/concurrent/executor/serialized_execution.rb:96:in `work'
concurrent-ruby-1.1.5/lib/concurrent/executor/serialized_execution.rb:77:in `block in call_job'
concurrent-ruby-1.1.5/lib/concurrent/executor/ruby_thread_pool_executor.rb:348:in `run_task'
concurrent-ruby-1.1.5/lib/concurrent/executor/ruby_thread_pool_executor.rb:337:in `block (3 levels) in create_worker'
concurrent-ruby-1.1.5/lib/concurrent/executor/ruby_thread_pool_executor.rb:320:in `loop'
concurrent-ruby-1.1.5/lib/concurrent/executor/ruby_thread_pool_executor.rb:320:in `block (2 levels) in create_worker'
concurrent-ruby-1.1.5/lib/concurrent/executor/ruby_thread_pool_executor.rb:319:in `catch'
concurrent-ruby-1.1.5/lib/concurrent/executor/ruby_thread_pool_executor.rb:319:in `block in create_worker'

Example:

require 'concurrent'
require 'concurrent-edge'

class Counter < Concurrent::Actor::Context
  def initialize(initial_value)
    @count = initial_value
  end

  def on_message(message)
    if Integer === message
      @count += message
    else
      raise "error"
    end
  end
end

def run
  counter = Counter.spawn(:first, 5)
  counter.tell("1")
end
run
sleep 3

Result:

2019-05-25 06:27:07.466] ERROR -- /first: error (RuntimeError)
/home/inecas/tmp/actor.rb:13:in `on_message'
/home/inecas/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/context.rb:46:in `on_envelope'
/home/inecas/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/behaviour/executes_context.rb:7:in `on_envelope'
/home/inecas/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/concurrent-ruby-edge-0.4.1/lib-edge/concurrent/actor/behaviour/abstract.rb:25:in `pass'
# the backtrace goes on with concurrent-ruby internal details

Desired would be something like

2019-05-25 06:27:07.466] ERROR -- /first: error (RuntimeError)
/home/inecas/tmp/actor.rb:13:in `on_message'
[ concurrent-ruby ]
/home/inecas/tmp/actor.rb:20:in `run'

This is very bad developer experience and makes it very hard to deal with the code that is using actors or other concurrent-ruby abstractions.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Trace actor error handling from concurrent/actor/context.rb through the actor behaviour and executor paths shown in the backtrace, starting with the provided actor example. Compare the current error output with the desired output; done means errors retain the user call site while separating or omitting concurrent-ruby internals.

Written by the indexing model from the issue text.

Assessment

Tech stack
ruby
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.