ediverse Explore the platform

Spotlight PEPPOL BIS Billing 3.0 The EU e-invoicing mandate is here — France Sept 2026, Belgium Jan 2026, Germany 2025.

Session Window

How to group events naturally clustered in activity bursts, without alignment to a fixed calendar.

Problem

Tumbling and sliding windows align to external clocks (every full hour, every 30 seconds). Many real activities do not follow a regular tempo: a user clicks 12 times in 2 minutes then disappears for 4 hours; an EDI partner sends 200 invoices in 5 minutes then nothing overnight. For these cases, we want to group events close in time into distinct sessions — unique business or user behaviour — separated by inactivity periods (gaps).

Forces

  • No temporal alignment — each key has its own sessions with variable start and end.
  • Gap definition: too short = fragmented sessions; too long = artificially merged sessions.
  • Session merging: a late event may merge two previously-closed sessions — complex logic.
  • State: maintain one open session per key, release after gap.
  • High cost on very large cardinality — each key carries its session.

Solution

Define a gap G (inactivity duration after which the session is considered ended). An event at time t opens a session if none is active for that key. A subsequent event at t' < t+G extends the session. When the watermark passes t_last + G without a new event, the session closes and the aggregate is emitted. To handle late events, Flink allows merging: if an event arrives and falls between two already-closed sessions separated by less than G, both sessions are merged retroactively. Flink implementation: stream.keyBy(partnerId).window(EventTimeSessionWindows.withGap(Time.minutes(30))).aggregate(new BatchSizeAggregator()).

Structure

Partner A timeline (gap = 30 min):
Time:  09:00  09:05  09:08  09:15 ...... 11:45  11:50  11:52
Event:  ●      ●      ●      ●            ●      ●      ●
        └─── Session 1 (4 events) ─┘     └ Session 2 (3) ─┘
              gap < 30min                  4h gap, > 30min
                                          → previous session closed

Partner B timeline:
Time:  09:30  09:50  10:25
Event:  ●      ●      ●
        └─ Session 1 ─┘
              all gaps < 30min → single session of 3 events

Late event arriving at 09:20 for partner A:
  Falls between sessions 1 (09:00-09:15) and an earlier session?
  → If yes and gap allows, merge sessions retroactively
  → If no, may create a new singleton session

EDI implementation

Typical EDI cases. (1) Partner batch detection: group all INVOIC received from the same partner separated by less than 30 minutes into one "send session", to compute the average batch size and timing — useful to optimise acknowledgement SLA (send one APERAK grouped per session instead of one per message). (2) Long-running saga workflow: an ORDERS/ORDRSP/DESADV/RECADV/INVOIC cycle may span several days but with activity bursts; a session window with 7-day gap per purchase-order number groups the events of one business saga. (3) Attack detection: if a partner sends an abnormally short session with many errors, it is typically a bad deployment or a replaying robot; alert on the pattern. For these cases, do not forget to purge state on session close — without that, RocksDB blows up within weeks.

Anti-patterns

  • Gap too short (e.g. 30 seconds for human-driven messages) — fragments real sessions into dozens of pieces.
  • Gap too long (e.g. 4h for web sessions) — merges two days of use into a single session.
  • No post-close TTL — state of a key inactive for 6 months remains forever.
  • Per-event expensive aggregate computation instead of incremental — every arrival recomputes everything.
  • Ignoring merging — a late event can break already-emitted aggregates.

Sources