Module: EcfDgii::Polling

Defined in:
lib/ecf_dgii/polling.rb

Overview

Polling logic with exponential backoff.

Usage:

EcfDgii::Polling.poll_until_complete do
  client.query_ecf(rnc, encf)
end

Constant Summary collapse

TERMINAL_PROGRESS =

Terminal progress values matching the ECF API contract.

- "Finished" → ECF processing completed successfully
- "Error"    → ECF processing failed (throws EcfError in client)
%w[Finished Error].freeze

Class Method Summary collapse

Class Method Details

.poll_until_complete(options = nil) ⇒ Object

Poll a block until its result indicates completion, using exponential backoff.

Parameters:

  • options (PollingOptions, nil) (defaults to: nil)

    Polling configuration

Yield Returns:

  • (Object)

    An object that responds to #progress

Returns:

  • (Object)

    The final result when progress is terminal

Raises:



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/ecf_dgii/polling.rb', line 58

def self.poll_until_complete(options = nil)
  opts = options || PollingOptions.new
  delay = opts.initial_delay
  retries = 0
  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)

  loop do
    # Check cancellation before each iteration
    if opts.cancellation && opts.cancellation.call
      raise PollingTimeoutError, "Polling was cancelled"
    end

    result = yield

    progress = extract_progress(result)

    return result if TERMINAL_PROGRESS.include?(progress)

    retries += 1

    if opts.max_retries > 0 && retries >= opts.max_retries
      raise PollingMaxRetriesError.new(opts.max_retries)
    end

    if opts.timeout && opts.timeout > 0
      elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
      if elapsed >= opts.timeout
        raise PollingTimeoutError,
              "Polling timed out after #{opts.timeout}s (last progress: #{progress})"
      end
    end

    sleep(delay)
    delay = [delay * opts.backoff_multiplier, opts.max_delay].min
  end
end