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



645
646
647
# File 'lib/concurrent/edge/future.rb', line 645

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

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



625
626
627
# File 'lib/concurrent/edge/future.rb', line 625

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:



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

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

#exception(*args) ⇒ Object

Examples:

allows failed Future to be risen

raise Concurrent.future.fail


602
603
604
605
606
607
608
609
610
611
# File 'lib/concurrent/edge/future.rb', line 602

def exception(*args)
  raise 'obligation is not failed' unless failed?
  reason = @State.get.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 = @State.get) ⇒ Boolean

Has Future been failed?

Returns:

  • (Boolean)


543
544
545
# File 'lib/concurrent/edge/future.rb', line 543

def failed?(state = @State.get)
  state.completed? && !state.success?
end

#flat(level = 1) ⇒ Object

zips with the Future in the value

Examples:

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


640
641
642
# File 'lib/concurrent/edge/future.rb', line 640

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

#fulfilled?Boolean

Returns:

  • (Boolean)


536
537
538
539
# File 'lib/concurrent/edge/future.rb', line 536

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



705
706
707
# File 'lib/concurrent/edge/future.rb', line 705

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

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

Returns self.

Yields:

  • (reason)

    executed sync when failed?

Returns:

  • self



717
718
719
# File 'lib/concurrent/edge/future.rb', line 717

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

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

Returns self.

Yields:

  • (value)

    executed async on ‘executor` when success

Returns:

  • self



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

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

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

Returns self.

Yields:

  • (value)

    executed sync when success

Returns:

  • self



711
712
713
# File 'lib/concurrent/edge/future.rb', line 711

def on_success!(&callback)
  add_callback :pr_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



565
566
567
568
# File 'lib/concurrent/edge/future.rb', line 565

def reason(timeout = nil)
  touch
  @State.get.reason if wait_until_complete timeout
end

#rejected?Boolean

Returns:

  • (Boolean)


547
548
549
550
# File 'lib/concurrent/edge/future.rb', line 547

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

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

Yields:

  • (reason)

    executed only on parent failure

Returns:



633
634
635
# File 'lib/concurrent/edge/future.rb', line 633

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



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

def result(timeout = nil)
  touch
  @State.get.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:



657
658
659
660
661
662
663
# File 'lib/concurrent/edge/future.rb', line 657

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 527


#success?(state = @State.get) ⇒ Boolean

Has Future been success?

Returns:

  • (Boolean)


532
533
534
# File 'lib/concurrent/edge/future.rb', line 532

def success?(state = @State.get)
  state.completed? && state.success?
end

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

Yields:

  • (value)

    executed only on parent success

Returns:



615
616
617
# File 'lib/concurrent/edge/future.rb', line 615

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



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

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

#then_push(channel) ⇒ Object

Note:

may block

Note:

only proof of concept



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

def then_push(channel)
  on_success(:io) { |value| channel.push value }
end

#then_select(*channels) ⇒ Future

Zips with selected value form the suplied channels

Returns:



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

def then_select(*channels)
  ZipPromise.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



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

def value(timeout = nil)
  touch
  @State.get.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



595
596
597
598
# File 'lib/concurrent/edge/future.rb', line 595

def value!(timeout = nil)
  touch
  @State.get.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



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

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:



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

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

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

Zip with future producing new Future

Returns:



679
680
681
682
683
684
685
# File 'lib/concurrent/edge/future.rb', line 679

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