shunping opened a new pull request, #40879:
URL: https://github.com/apache/beam/pull/40879

   ## Summary
   The `Trigger` message in `beam_runner_api.proto` only says when each trigger 
is *ready* to fire. It doesn't say what happens when a trigger **finishes**, 
meaning it will never fire again. Runners depend on that: when a window's root 
trigger finishes, the window is closed, no more panes are emitted, and later 
elements are dropped.
   Java and Python already behave this way, but the rules live only in SDK and 
runner code. Prism behaved differently until #<Prism PR>. This PR adds the 
rules to the model as comments only; there are no schema changes.
   
   ## Changes
   **`Trigger` header comment**
   - Triggers are evaluated per key and window; each time the root trigger is 
ready, the current pane is output.
   - When the *root* trigger finishes, the window is closed for that key:
     - the firing that finished it is the final pane (`PaneInfo.is_last`);
     - no further panes are produced, including at end of window or window 
expiry, regardless of `ClosingBehavior` / `OnTimeBehavior`;
     - elements arriving after the window closes are dropped, whether or not 
they are late relative to the watermark.
   - A root trigger that may finish before the window expires can lose data, so 
SDKs call it "unsafe". `Repeat` makes a trigger never finish. Runners must 
still implement the closed-window rules for pipelines that use finishing 
triggers.
   - A finishing *subtrigger* doesn't close the window on its own; it only 
affects its parent.
   
   **When each trigger type finishes**
   
   | Trigger | Finishes | Java state machine |
   |---|---|---|
   | `AfterAll` | after firing once | 
[AfterAllStateMachine#L111](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/runners/core-java/src/main/java/org/apache/beam/runners/core/triggers/AfterAllStateMachine.java#L111)
 |
   | `AfterAny` | after firing once | 
[AfterFirstStateMachine#L108](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/runners/core-java/src/main/java/org/apache/beam/runners/core/triggers/AfterFirstStateMachine.java#L108)
 |
   | `AfterEach` | when its last subtrigger finishes | 
[AfterEachStateMachine#L161](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/runners/core-java/src/main/java/org/apache/beam/runners/core/triggers/AfterEachStateMachine.java#L161)
 |
   | `AfterEndOfWindow` | with no `late_firings`, on its firing after end of 
window; with `late_firings`, never before expiry (late trigger repeats 
implicitly) | 
[AfterWatermarkStateMachine#L196-L204](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/runners/core-java/src/main/java/org/apache/beam/runners/core/triggers/AfterWatermarkStateMachine.java#L196-L204),
 
[#L258](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/runners/core-java/src/main/java/org/apache/beam/runners/core/triggers/AfterWatermarkStateMachine.java#L258)
 |
   | `AfterProcessingTime`, `AfterSynchronizedProcessingTime` | after firing 
once | 
[AfterDelayFromFirstElementStateMachine#L231](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/runners/core-java/src/main/java/org/apache/beam/runners/core/triggers/AfterDelayFromFirstElementStateMachine.java#L231)
 |
   | `ElementCount` | after firing once | 
[AfterPaneStateMachine#L133](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/runners/core-java/src/main/java/org/apache/beam/runners/core/triggers/AfterPaneStateMachine.java#L133)
 |
   | `OrFinally` | when `finally` fires, or `main` finishes, whichever comes 
first | 
[OrFinallyStateMachine#L77-L104](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/runners/core-java/src/main/java/org/apache/beam/runners/core/triggers/OrFinallyStateMachine.java#L77-L104)
 |
   | `Repeat` | never; the subtrigger is reset when it finishes | 
[RepeatedlyStateMachine#L89](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/runners/core-java/src/main/java/org/apache/beam/runners/core/triggers/RepeatedlyStateMachine.java#L89)
 |
   | `Default`, `Always` | never | |
   | `Never` | never before window expiry | |
   
   **`ClosingBehavior.EMIT_ALWAYS`**: notes that it doesn't apply if the window 
was already closed by a finished root trigger. In that case no pane is emitted 
at expiry.
   
   ## References
   **What "finishing" a root trigger means**
   - Java `Trigger` javadoc, 
[Trigger.java#L41-L45](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/windowing/Trigger.java#L41-L45):
     > When the root trigger finishes (indicating it will never fire again), 
the window is closed and any new elements assigned to that window are discarded.
   - Java runner, 
[ReduceFnRunner.java](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/runners/core-java/src/main/java/org/apache/beam/runners/core/ReduceFnRunner.java):
     - 
[L643-L655](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/runners/core-java/src/main/java/org/apache/beam/runners/core/ReduceFnRunner.java#L643-L655):
 elements for a closed window are dropped and counted in 
`droppedDueToClosedWindow`.
     - 
[L853-L866](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/runners/core-java/src/main/java/org/apache/beam/runners/core/ReduceFnRunner.java#L853-L866)
 and 
[L879-L883](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/runners/core-java/src/main/java/org/apache/beam/runners/core/ReduceFnRunner.java#L879-L883):
 end-of-window and expiry panes fire only while `windowIsActiveAndOpen()`, i.e. 
the window is active and its trigger hasn't finished. So a closed window gets 
no extra pane, whatever `ClosingBehavior` says.
   - Python: once a window's trigger finishes, `GeneralTriggerDriver` in 
[trigger.py](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/sdks/python/apache_beam/transforms/trigger.py)
 marks it with a `TOMBSTONE` and skips later elements for it.
   - Programming guide, [§9.5 Composite 
triggers](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/website/www/site/content/en/documentation/programming-guide.md#L6082-L6109):
 triggers can emit "repeatedly, at most once", and `orFinally` makes a trigger 
"fire one final time and never fire again".
   
   **"Unsafe" triggers**
   - Java `Trigger.mayFinish()`, 
[Trigger.java#L143-L147](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/windowing/Trigger.java#L143-L147):
 "A top level trigger that finishes can cause data loss, so is rejected by 
GroupByKey validation."
   - Java `GroupByKey`, 
[GroupByKey.java#L185-L245](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/GroupByKey.java#L185-L245):
 `triggerIsSafe` rejects root triggers that may finish, except `Never`, and 
end-of-window triggers with zero allowed lateness or with late firings. The 
error reads "Unsafe trigger '…' may lose data, did you mean to wrap it in 
`Repeatedly.forever(...)`?".
   - Python:
     - 
[trigger.py#L160-L181](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/sdks/python/apache_beam/transforms/trigger.py#L160-L181):
 `DataLossReason.MAY_FINISH`, "data that comes in after the trigger may be 
lost. Example: AfterCount(1) will stop firing after the first element."
     - 
[trigger.py#L269-L294](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/sdks/python/apache_beam/transforms/trigger.py#L269-L294):
 `may_lose_data()`.
     - 
[core.py#L3524-L3540](https://github.com/apache/beam/blob/0c5adeaff12d46edffa88adbb43fd4ea8fad0f26/sdks/python/apache_beam/transforms/core.py#L3524-L3540):
 `GroupByKey` raises "Unsafe trigger … may lose data" unless 
`--allow_unsafe_triggers` is set.
   - Design doc: [Guard against "Trigger Finishing", a data loss 
risk](https://s.apache.org/finishing-triggers-drop-data), linked from the Java 
error message.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to