Sha256: fa286aa583547bc77a813c866cf24d7eb1ed650dc1ec9c27dc86b6e4581b2cd8

Contents?: true

Size: 1.33 KB

Versions: 7

Compression:

Stored size: 1.33 KB

Contents

# frozen_string_literal: true

export_default :CancelScope

require 'fiber'

Exceptions = import('./exceptions')

# A cancellation scope that can be used to cancel an asynchronous task
class CancelScope
  def initialize(opts = {}, &block)
    @opts = opts
    @fibers = []
    start_timeout_waiter if @opts[:timeout]
    call(&block) if block
  end

  def error_class
    @opts[:mode] == :cancel ? Exceptions::Cancel : Exceptions::MoveOn
  end

  def cancel!
    @cancelled = true
    @fibers.each do |f|
      f.schedule error_class.new(self, @opts[:value])
    end
    @on_cancel&.()
  end

  def start_timeout_waiter
    @timeout_waiter = spin do
      sleep @opts[:timeout]
      @timeout_waiter = nil
      cancel!
    end
  end

  def stop_timeout_waiter
    return unless @timeout_waiter

    @timeout_waiter.stop
    @timeout_waiter = nil
  end

  def reset_timeout
    return unless @timeout_waiter

    @timeout_waiter.stop
    start_timeout_waiter
  end

  # def disable
  #   @timeout&.stop
  # end

  def call
    fiber = Fiber.current
    @fibers << fiber
    yield self
  rescue Exceptions::MoveOn => e
    e.scope == self ? e.value : raise(e)
  ensure
    @fibers.delete fiber
    stop_timeout_waiter if @fibers.empty? && @timeout_waiter
  end

  def on_cancel(&block)
    @on_cancel = block
  end

  def cancelled?
    @cancelled
  end
end

Version data entries

7 entries across 7 versions & 1 rubygems

Version Path
polyphony-0.31 lib/polyphony/core/cancel_scope.rb
polyphony-0.30 lib/polyphony/core/cancel_scope.rb
polyphony-0.29 lib/polyphony/core/cancel_scope.rb
polyphony-0.28 lib/polyphony/core/cancel_scope.rb
polyphony-0.27 lib/polyphony/core/cancel_scope.rb
polyphony-0.26 lib/polyphony/core/cancel_scope.rb
polyphony-0.25 lib/polyphony/core/cancel_scope.rb