Class: WhittakerTech::Aeon::Projector

Inherits:
Object
  • Object
show all
Defined in:
app/services/whittaker_tech/aeon/projector.rb

Overview

Stateless service that expands an Allocation into materialised Occurrence rows. Operates within a single +FOR UPDATE NOWAIT+ transaction to guarantee exclusive access.

Projection is: - Monotonic — +projected_until+ only moves forward. - Idempotent — +INSERT ON CONFLICT DO NOTHING+ prevents duplicates. - Bounded — capped by Configuration#max_projection_window and the allocation’s +valid_to+. - Batched — large result sets are sliced into UPSERT_BATCH_SIZE chunks to prevent unbounded SQL statements.

Examples:

Project an allocation 30 days ahead

Projector.call(allocation_id: alloc.id, target_until: 30.days.from_now)

Constant Summary collapse

UPSERT_BATCH_SIZE =

Maximum number of rows per +insert_all+ call.

5_000

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(allocation_id:, target_until:) ⇒ Projector

Returns a new instance of Projector.

Parameters:

  • allocation_id (String)

    UUID of the allocation to project

  • target_until (Time)

    desired projection horizon



31
32
33
34
# File 'app/services/whittaker_tech/aeon/projector.rb', line 31

def initialize(allocation_id:, target_until:)
  @allocation_id = allocation_id
  @target_until = target_until
end

Class Method Details

.call(allocation_id:, target_until:) ⇒ void

This method returns an undefined value.

Parameters:

  • allocation_id (String)

    UUID of the allocation to project

  • target_until (Time)

    desired projection horizon



25
26
27
# File 'app/services/whittaker_tech/aeon/projector.rb', line 25

def self.call(allocation_id:, target_until:)
  new(allocation_id: allocation_id, target_until: target_until).call
end

Instance Method Details

#callvoid

This method returns an undefined value.

Locks the allocation, expands occurrences from +projected_until+ to the capped horizon, upserts rows, and advances the frontier.



40
41
42
43
44
45
46
47
48
49
50
51
# File 'app/services/whittaker_tech/aeon/projector.rb', line 40

def call
  Allocation.transaction do
    Allocation.connection.execute("SET LOCAL aeon.bypass_guard = 'true'")
    allocation = lock_allocation!
    return if already_projected?(allocation)

    cap_target!(allocation)
    rows = expand(allocation)
    upsert!(rows) if rows.any?
    advance_frontier!(allocation)
  end
end