Class: Concurrent::Edge::Future

Inherits:
Event
  • Object
show all
Defined in:
lib/concurrent/edge/future.rb

Overview

Represents a value which will become available in future. May fail with a reason instead.

Direct Known Subclasses

CompletableFuture

Instance Method Summary collapse

Methods inherited from Event

#chain, #completed?, #default_executor, #initialize, #inspect, #on_completion, #on_completion!, #pending?, #set, #to_s, #unscheduled?, #wait

Constructor Details

This class inherits a constructor from Concurrent::Edge::Event

Instance Method Details

#any(*futures) ⇒ Future Also known as: |

Returns which has first completed value from futures.

Returns:

  • (Future)

    which has first completed value from futures



672
673
674
# File 'lib/concurrent/edge/future.rb', line 672

def any(*futures)
  AnyCompletePromise.new([self, *futures], @DefaultExecutor).future
end

#chain_completable(completable_future) ⇒ Object Also known as: tangle



652
653
654
# File 'lib/concurrent/edge/future.rb', line 652

def chain_completable(completable_future)
  on_completion! { completable_future.complete_with internal_state }
end

#delayFuture

Inserts delay into the chain of Futures making rest of it lazy evaluated.

Returns:



678
679
680
# File 'lib/concurrent/edge/future.rb', line 678

def delay
  ZipFutureEventPromise.new(self, DelayPromise.new(@DefaultExecutor).future, @DefaultExecutor).future
end

#exception(*args) ⇒ Object

Examples:

allows failed Future to be risen

raise Concurrent.future.fail


629
630
631
632
633
634
635
636
637
638
# File 'lib/concurrent/edge/future.rb', line 629

def exception(*args)
  raise 'obligation is not failed' unless failed?
  reason = internal_state.reason
  if reason.is_a?(::Array)
    reason.each { |e| log ERROR, 'Edge::Future', e }
    Concurrent::Error.new 'multiple exceptions, inspect log'
  else
    reason.exception(*args)
  end
end

#failed?(state = internal_state) ⇒ Boolean

Has Future been failed?

Returns:

  • (Boolean)


570
571
572
# File 'lib/concurrent/edge/future.rb', line 570

def failed?(state = internal_state)
  state.completed? && !state.success?
end

#flat(level = 1) ⇒ Object

zips with the Future in the value

Examples:

Concurrent.future { Concurrent.future { 1 } }.flat.value # => 1


667
668
669
# File 'lib/concurrent/edge/future.rb', line 667

def flat(level = 1)
  FlatPromise.new(self, level, @DefaultExecutor).future
end

#fulfilled?Boolean

Returns:

  • (Boolean)


563
564
565
566
# File 'lib/concurrent/edge/future.rb', line 563

def fulfilled?
  deprecated_method 'fulfilled?', 'success?'
  success?
end

#on_failure(executor = nil) {|reason| ... } ⇒ Object

Returns self.

Yields:

  • (reason)

    executed async on ‘executor` when failed?

Returns:

  • self



732
733
734
# File 'lib/concurrent/edge/future.rb', line 732

def on_failure(executor = nil, &callback)
  add_callback :async_callback_on_failure, executor || @DefaultExecutor, callback
end

#on_failure! {|reason| ... } ⇒ Object

Returns self.

Yields:

  • (reason)

    executed sync when failed?

Returns:

  • self



744
745
746
# File 'lib/concurrent/edge/future.rb', line 744

def on_failure!(&callback)
  add_callback :callback_on_failure, callback
end

#on_success(executor = nil) {|value| ... } ⇒ Object

Returns self.

Yields:

  • (value)

    executed async on ‘executor` when success

Returns:

  • self



726
727
728
# File 'lib/concurrent/edge/future.rb', line 726

def on_success(executor = nil, &callback)
  add_callback :async_callback_on_success, executor || @DefaultExecutor, callback
end

#on_success! {|value| ... } ⇒ Object

Returns self.

Yields:

  • (value)

    executed sync when success

Returns:

  • self



738
739
740
# File 'lib/concurrent/edge/future.rb', line 738

def on_success!(&callback)
  add_callback :callback_on_success, callback
end

#reason(timeout = nil) ⇒ Exception?

Note:

If the Future can have value ‘nil` then it cannot be distinquished from `nil` returned on timeout. In this case is better to use first `wait` then `value` (or similar).

Note:

a thread should wait only once! For repeated checking use faster ‘completed?` check. If thread waits periodically it will dangerously grow the waiters stack.

Returns the reason of the Future’s failure.

Returns:

  • (Exception, nil)

    the reason of the Future’s failure



592
593
594
595
# File 'lib/concurrent/edge/future.rb', line 592

def reason(timeout = nil)
  touch
  internal_state.reason if wait_until_complete timeout
end

#rejected?Boolean

Returns:

  • (Boolean)


574
575
576
577
# File 'lib/concurrent/edge/future.rb', line 574

def rejected?
  deprecated_method 'rejected?', 'failed?'
  failed?
end

#rescue(executor = nil) {|reason| ... } ⇒ Future

Yields:

  • (reason)

    executed only on parent failure

Returns:



660
661
662
# File 'lib/concurrent/edge/future.rb', line 660

def rescue(executor = nil, &callback)
  RescuePromise.new(self, @DefaultExecutor, executor || @DefaultExecutor, &callback).future
end

#result(timeout = nil) ⇒ Array(Boolean, Object, Exception)?

Note:

If the Future can have value ‘nil` then it cannot be distinquished from `nil` returned on timeout. In this case is better to use first `wait` then `value` (or similar).

Note:

a thread should wait only once! For repeated checking use faster ‘completed?` check. If thread waits periodically it will dangerously grow the waiters stack.

Returns triplet of success, value, reason.

Returns:

  • (Array(Boolean, Object, Exception), nil)

    triplet of success, value, reason



600
601
602
603
# File 'lib/concurrent/edge/future.rb', line 600

def result(timeout = nil)
  touch
  internal_state.result if wait_until_complete timeout
end

#schedule(intended_time) ⇒ Future

Schedules rest of the chain for execution with specified time or on specified time

Returns:



684
685
686
687
688
689
690
# File 'lib/concurrent/edge/future.rb', line 684

def schedule(intended_time)
  chain do
    ZipFutureEventPromise.new(self,
                              ScheduledPromise.new(@DefaultExecutor, intended_time).event,
                              @DefaultExecutor).future
  end.flat
end

#state:pending, ...

Returns:

  • (:pending, :success, :failed)


# File 'lib/concurrent/edge/future.rb', line 554


#success?(state = internal_state) ⇒ Boolean

Has Future been success?

Returns:

  • (Boolean)


559
560
561
# File 'lib/concurrent/edge/future.rb', line 559

def success?(state = internal_state)
  state.completed? && state.success?
end

#then(executor = nil) {|value| ... } ⇒ Future

Yields:

  • (value)

    executed only on parent success

Returns:



642
643
644
# File 'lib/concurrent/edge/future.rb', line 642

def then(executor = nil, &callback)
  ThenPromise.new(self, @DefaultExecutor, executor || @DefaultExecutor, &callback).future
end

#then_ask(actor) ⇒ Future

Asks the actor with its value.

Returns:

  • (Future)

    new future with the response form the actor



648
649
650
# File 'lib/concurrent/edge/future.rb', line 648

def then_ask(actor)
  self.then { |v| actor.ask(v) }.flat
end

#then_put(channel) ⇒ Object

Note:

may block

Note:

only proof of concept



720
721
722
# File 'lib/concurrent/edge/future.rb', line 720

def then_put(channel)
  on_success(:io) { |value| channel.put value }
end

#then_select(*channels) ⇒ Future

Zips with selected value form the suplied channels

Returns:



694
695
696
# File 'lib/concurrent/edge/future.rb', line 694

def then_select(*channels)
  ZipFuturesPromise.new([self, Concurrent.select(*channels)], @DefaultExecutor).future
end

#value(timeout = nil) ⇒ Object?

Note:

If the Future can have value ‘nil` then it cannot be distinquished from `nil` returned on timeout. In this case is better to use first `wait` then `value` (or similar).

Note:

a thread should wait only once! For repeated checking use faster ‘completed?` check. If thread waits periodically it will dangerously grow the waiters stack.

Returns the value of the Future when success, nil on timeout.

Returns:

  • (Object, nil)

    the value of the Future when success, nil on timeout



584
585
586
587
# File 'lib/concurrent/edge/future.rb', line 584

def value(timeout = nil)
  touch
  internal_state.value if wait_until_complete timeout
end

#value!(timeout = nil) ⇒ Object?

Note:

If the Future can have value ‘nil` then it cannot be distinquished from `nil` returned on timeout. In this case is better to use first `wait` then `value` (or similar).

Note:

a thread should wait only once! For repeated checking use faster ‘completed?` check. If thread waits periodically it will dangerously grow the waiters stack.

Wait until Future is #complete?

Parameters:

  • timeout (Numeric) (defaults to: nil)

    the maximum time in second to wait.

Returns:

  • (Object, nil)

Raises:

  • reason on failure



622
623
624
625
# File 'lib/concurrent/edge/future.rb', line 622

def value!(timeout = nil)
  touch
  internal_state.value if wait_until_complete! timeout
end

#wait!(timeout = nil) ⇒ Event, ...

Note:

a thread should wait only once! For repeated checking use faster ‘completed?` check. If thread waits periodically it will dangerously grow the waiters stack.

Wait until Future is #complete?

Parameters:

  • timeout (Numeric) (defaults to: nil)

    the maximum time in second to wait.

Returns:

  • (Event, true, false)

    self or true/false if timeout is used

Raises:

  • reason on failure



610
611
612
613
614
# File 'lib/concurrent/edge/future.rb', line 610

def wait!(timeout = nil)
  touch
  result = wait_until_complete!(timeout)
  timeout ? result : self
end

#with_default_executor(executor) ⇒ Future

Changes default executor for rest of the chain

Returns:



700
701
702
# File 'lib/concurrent/edge/future.rb', line 700

def with_default_executor(executor)
  FutureWrapperPromise.new(self, executor).future
end

#zip(other) ⇒ Future Also known as: &

Zip with future producing new Future

Returns:



706
707
708
709
710
711
712
# File 'lib/concurrent/edge/future.rb', line 706

def zip(other)
  if other.is_a?(Future)
    ZipFutureFuturePromise.new(self, other, @DefaultExecutor).future
  else
    ZipFutureEventPromise.new(self, other, @DefaultExecutor).future
  end
end