You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
FailSafe's docs (docs/doc/10-examples/190-error-handling.md, "Continue Processing on Failure") claim: "One of the most powerful features of FailSafe is that it allows the chain to continue processing other items even if one fails." This isn't true today.
FailSafeOperation::repeatOnItem() re-throws once nbAttempts is exhausted. That propagates through ChainProcessor::process(), which has no per-item recovery — it logs and re-throws, aborting the entire run. Confirmed by the library's own test, FailSafeOperationTest::testToManyFail(): given 2 permanently-failing items in the input iterator, the second item is never even attempted — the first item's exhausted retries kill the whole process() call.
Proposed solution
Give FailSafeConfig an optional onFailure: ?ChainConfig sub-chain, the same pattern IfConfig already uses for then/else — not a boolean flag, not a new item type. When retries are exhausted:
No onFailure configured (default null) → re-throw, exactly like today. Fully backward compatible.
onFailure configured → the failed item runs through that chain instead of aborting the run. It's a normal ChainConfig, so it can do anything — write it to a reject file, alert, log richly — not just a fixed "drop with a reason" behavior.
FailSafeOperation builds $onFailureProcessor from it (when present) the same way it already builds $chainProcessor, and on final failure runs the item through $onFailureProcessor->processGenerator(...) instead of re-throwing. This also means FailSafeOperation::getChainProcessors() (see #74) should return both $chainProcessor and $onFailureProcessor when present, so the failure branch shows up in Mermaid diagrams too.
Compatibility
No V3. New optional parameter defaulting to null; existing configs behave identically.
Scope
FailSafeConfig, FailSafeOperation
Tests: extend/mirror testToManyFail for the onFailure case — assert the second item does get processed, and that the failed item reaches the onFailure chain
Docs: 190-error-handling.md's "Continue Processing on Failure" section needs to actually match reality once this ships
Problem
FailSafe's docs (
docs/doc/10-examples/190-error-handling.md, "Continue Processing on Failure") claim: "One of the most powerful features of FailSafe is that it allows the chain to continue processing other items even if one fails." This isn't true today.FailSafeOperation::repeatOnItem()re-throws oncenbAttemptsis exhausted. That propagates throughChainProcessor::process(), which has no per-item recovery — it logs and re-throws, aborting the entire run. Confirmed by the library's own test,FailSafeOperationTest::testToManyFail(): given 2 permanently-failing items in the input iterator, the second item is never even attempted — the first item's exhausted retries kill the wholeprocess()call.Proposed solution
Give
FailSafeConfigan optionalonFailure: ?ChainConfigsub-chain, the same patternIfConfigalready uses forthen/else— not a boolean flag, not a new item type. When retries are exhausted:onFailureconfigured (defaultnull) → re-throw, exactly like today. Fully backward compatible.onFailureconfigured → the failed item runs through that chain instead of aborting the run. It's a normalChainConfig, so it can do anything — write it to a reject file, alert, log richly — not just a fixed "drop with a reason" behavior.FailSafeOperationbuilds$onFailureProcessorfrom it (when present) the same way it already builds$chainProcessor, and on final failure runs the item through$onFailureProcessor->processGenerator(...)instead of re-throwing. This also meansFailSafeOperation::getChainProcessors()(see #74) should return both$chainProcessorand$onFailureProcessorwhen present, so the failure branch shows up in Mermaid diagrams too.Compatibility
No V3. New optional parameter defaulting to
null; existing configs behave identically.Scope
FailSafeConfig,FailSafeOperationtestToManyFailfor theonFailurecase — assert the second item does get processed, and that the failed item reaches theonFailurechain190-error-handling.md's "Continue Processing on Failure" section needs to actually match reality once this ships