class Ractor::Server::Request

Attributes

info[R]
initiating_ractor[R]
response_to[R]
sync[R]

Public Class Methods

message(*args, **options) click to toggle source
# File lib/ractor/server/request.rb, line 94
def message(*args, **options)
  request = new(**options)
  [request, *args].freeze
end
new(response_to: nil, sync: nil, info: nil) click to toggle source
# File lib/ractor/server/request.rb, line 14
def initialize(response_to: nil, sync: nil, info: nil)
  @response_to = response_to
  @initiating_ractor = Ractor.current
  @sync = sync
  @info = info # for display only
  enforce_valid_sync!
  Ractor.make_shareable(self)
end
pending_receive_conclusion() click to toggle source
# File lib/ractor/server/request.rb, line 103
def pending_receive_conclusion
  ::Ractor.current[:ractor_server_request_receive_conclusion] ||= ::ObjectSpace::WeakMap.new
end
pending_send_conclusion() click to toggle source
# File lib/ractor/server/request.rb, line 99
def pending_send_conclusion
  ::Ractor.current[:ractor_server_request_send_conclusion] ||= ::ObjectSpace::WeakMap.new
end
receive_if(&block) click to toggle source
# File lib/ractor/server/request.rb, line 107
def receive_if(&block)
  message = ::Ractor.receive_if(&block)
  rq, = message
  rq.sync_after_receiving
  debug(:receive) { "Received #{message}" }
  message
end
send(ractor, *arguments, move: false, **options) click to toggle source
# File lib/ractor/server/request.rb, line 115
def send(ractor, *arguments, move: false, **options)
  message = Request.message(*arguments, **options)
  request, = message
  request.enforce_sync_when_sending!
  debug(:send) { "Sending #{message}" }
  ractor.send(message, move: move)
  request
end

Public Instance Methods

===(message) click to toggle source

Match any request that is a response to the receiver (or an array message starting with such)

# File lib/ractor/server/request.rb, line 24
def ===(message)
  request, = message

  match = request.is_a?(Request) && self == request.response_to

  debug(:receive) { "Request #{request.inspect} does not match #{self}" } unless match

  match
end
enforce_sync_when_sending!() click to toggle source

@api private

# File lib/ractor/server/request.rb, line 157
def enforce_sync_when_sending!
  # Only dynamic checks are done here; static validity checked in constructor
  case sync
  when :conclude, :interrupt
    registry = Request.pending_send_conclusion
    raise Talk::Error, "Request #{response_to} already answered" unless registry[response_to]

    registry[response_to] = false
    Request.pending_receive_conclusion[response_to.response_to] = false if sync == :interrupt
  when :ask, :converse
    Request.pending_receive_conclusion[self] = true
  end
end
inspect() click to toggle source
# File lib/ractor/server/request.rb, line 76
def inspect
  [
    '<Request',
    info,
    ("for: #{response_to}" if response_to),
    ("sync: #{sync}" if sync),
    "from: #{ractor_name(initiating_ractor)}>",
  ].compact.join(' ')
end
Also aliased as: to_s
receive() click to toggle source
# File lib/ractor/server/request.rb, line 71
def receive
  enforce_sync_when_receiving!
  unwrap(Request.receive_if(&self))
end
respond_to_ractor() click to toggle source
# File lib/ractor/server/request.rb, line 87
def respond_to_ractor
  response_to.initiating_ractor
end
send(*args, **options) click to toggle source

@return [Request]

# File lib/ractor/server/request.rb, line 39
def send(*args, **options)
  Request.send(initiating_ractor, *args, **options, response_to: self)
end
send_exception(exception) click to toggle source
# File lib/ractor/server/request.rb, line 67
def send_exception(exception)
  send(WrappedException.new(exception), sync: sync && :conclude)
end
sync_after_receiving() click to toggle source

@api private

# File lib/ractor/server/request.rb, line 172
def sync_after_receiving
  # Only dynamic checks are done here; static validity checked in constructor
  case sync
  when :conclude, :interrupt
    Request.pending_receive_conclusion[response_to] = false
    Request.pending_send_conclusion[response_to.response_to] = false if sync == :interrupt
  when :ask, :converse
    Request.pending_send_conclusion[self] = true
  end
end
to_proc() click to toggle source
# File lib/ractor/server/request.rb, line 34
def to_proc
  method(:===).to_proc
end
to_s()
Alias for: inspect

Private Instance Methods

enforce_sync_when_receiving!() click to toggle source

Receiver is request to receive a reply from

# File lib/ractor/server/request.rb, line 184
        def enforce_sync_when_receiving!
  case sync
  when :tell, :conclude, :interrupt
    raise Talk::Error, "Can not receive from a Request for a `#{sync}` sync: #{self}"
  when :ask, :converse
    return :ok if Request.pending_receive_conclusion[self]

    raise Talk::Error, "Can not receive as #{self} is already answered"
  end
end
enforce_valid_sync!() click to toggle source
# File lib/ractor/server/request.rb, line 199
        def enforce_valid_sync! # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
  case [response_to&.sync, sync]
  in [nil, nil]
    :ok_unsynchronized
  in [nil | :converse, :tell | :ask | :converse]
    :ok_talk
  in [:ask | :converse, :conclude]
    :ok_concluding
  in [:ask | :converse, :interrupt]
    raise Talk::Error, 'Can only interrupt a 2-level conversation' unless response_to.response_to&.converse?

    :ok_interrupting
  in [:tell | :conclude | :interrupt => from, _]
    raise Talk::Error, "Can not respond to a Request with `#{from.inspect}` sync"
  in [:ask, _]
    raise Talk::Error, 'Request with `ask` sync must be responded with a `conclude`' \
      "or `interrupt` sync, got #{sync.inspect}"
  in [_, nil]
    raise Talk::Error, "Specify sync to respond to a Request with #{sync.inspect}"
  else
    raise ArgumentError, "Unrecognized sync: #{sync.inspect}"
  end
end
ractor_name(ractor) click to toggle source
# File lib/ractor/server/request.rb, line 195
        def ractor_name(ractor)
  ractor.name || "##{ractor.to_s.match(/#(\d+) /)[1]}"
end
raise_exception(exc) click to toggle source
# File lib/ractor/server/request.rb, line 140
        def raise_exception(exc)
  raise exc unless WRAP_IN_REMOTE_ERROR

  if exc.exception.is_a?(Ractor::RemoteError)
    debug(:exception) { 'Received RemoteError, raising original cause' }
    raise exc.exception.cause
  else
    debug(:exception) { 'Received exception, raising RemoveError' }
    begin
      raise exc.exception
    rescue Exception
      raise Ractor::RemoteError # => sets `cause` to exc.exception
    end
  end
end
unwrap(message) click to toggle source
# File lib/ractor/server/request.rb, line 133
        def unwrap(message)
  _rq, arg = message
  raise_exception(arg) if arg.is_a?(WrappedException)

  message
end