Skip to content

Add retry mechanism and dynamic model loading to SONIC framework#27

Open
kakwok wants to merge 5 commits into
fastmachinelearning:masterfrom
kakwok:SonicRetryDML_CMSSW_17_0_0_pre2
Open

Add retry mechanism and dynamic model loading to SONIC framework#27
kakwok wants to merge 5 commits into
fastmachinelearning:masterfrom
kakwok:SonicRetryDML_CMSSW_17_0_0_pre2

Conversation

@kakwok

@kakwok kakwok commented Jun 24, 2026

Copy link
Copy Markdown

PR description:

Introduces a pluggable retry mechanism for SONIC inference clients and dynamic
model loading/unloading on the Triton fallback server. This enables automatic
recovery when a remote Triton server becomes unavailable during event processing.

Retry mechanism (SonicCore)

  • RetryActionBase: Plugin factory base class for retry strategies, with
    retry(), start(), finish() interface
  • RetrySameServerAction: Retries inference on the same server (configurable
    allowedTries)
  • SonicClientBase::finish(): Drives retry loop — on retryable failure
    (finish(false)), iterates through registered retry actions; on non-retryable
    failure (finish(false, eptr)), propagates exception directly

Retry with server failover (SonicTriton)

  • RetryActionDiffServer: On failure, queries TritonService::getBestServer()
    for an alternative healthy remote server, calls updateServer() + eval() to
    retry on the new server
  • RetryFallbackServerAction: Last-resort action — when all other retries are
    exhausted, lazily starts the fallback server (idempotent), dynamically loads the
    model to the fallback server via TritonClient::switchToFallback(), and retries locally. Fires at most
    once per inference call.
  • Server health tracking: TritonService maintains per-server health stats
    (liveness, readiness, failure count, queue time) via updateServerHealth(),
    used by getBestServer() to select the best candidate
  • Server selection preference: resolveServerName() prefers remote (non-fallback)
    servers when multiple servers provide the same model; getBestServer() excludes
    fallback servers from candidate pool

Async retry redesign (holder-based)

  • evaluate() (Async mode) creates an inner WaitingTaskWithArenaHolder per
    inference attempt — the gRPC callback calls doneWaiting() and returns
    immediately; finish()/retry()/updateServer() are scheduled as TBB tasks

Dynamic model loading (TritonService)

  • loadModel()/unloadModel() with reference counting for the fallback server
  • startFallbackServer() is idempotent; only started at preBeginJob for
    unassigned models (no remote server available)
  • Fallback server health entry properly registered in serversHealth_

Configuration

  • Retry actions configurable via Retry VPSet in client config
    (retryType, allowedTries)
  • customize.py updated with retry options, defaulted to add RetryFallbackServerAction as the last action.

PR validation:

retry_diffServer_fallback.log

…olve cmsTriton conflict in CMSSW_17_0_0_pre2.

Co-authored-by: Trevin Lee <trl008@ucsd.edu>
@kakwok
kakwok force-pushed the SonicRetryDML_CMSSW_17_0_0_pre2 branch from 0ea0d7a to 36ca055 Compare June 29, 2026 14:12
auto retryAction = RetryActionFactory::get()->create(actionType, retryPSet, this);
if (retryAction) {
//Convert to RetryActionPtr Type from raw pointer of retryAction
retryActions_.emplace_back(RetryActionPtr(retryAction.release()));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the explicit RetryActionPtr() needed here? usually for emplace_back(), it shouldn't be

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, because I think the RetryAction needs a custom deleter here, which is needed because it's a friend class of the SonicClient.
https://github.com/kakwok/cmssw/blob/SonicRetryDML_CMSSW_17_0_0_pre2/HeterogeneousCore/SonicCore/interface/SonicClientBase.h#L63-L69

Here's some more details from Claude:
RetryActionFactory::create() returns a std::unique_ptr<RetryActionBase> using the default deleter (std::default_delete<RetryActionBase>), since that's what edmplugin::PluginFactory hands back.
But retryActions_ stores your custom
RetryActionPtr = std::unique_ptr<RetryActionBase, RetryDeleter> — a different type, because RetryDeleter is a distinct functor from std::default_delete<RetryActionBase>.

Comment thread HeterogeneousCore/SonicCore/src/SonicClientBase.cc Outdated
Comment thread HeterogeneousCore/SonicTriton/interface/TritonService.h Outdated
Comment thread HeterogeneousCore/SonicTriton/python/customize.py Outdated
Comment thread HeterogeneousCore/SonicTriton/python/customize.py Outdated
Comment thread HeterogeneousCore/SonicTriton/test/RetryActionDiffServer.cc Outdated
Comment thread HeterogeneousCore/SonicTriton/test/RetryActionDiffServer.cc Outdated
Comment thread HeterogeneousCore/SonicTriton/test/RetryActionDiffServer.cc Outdated
Comment thread HeterogeneousCore/SonicTriton/test/BuildFile.xml Outdated
Comment on lines +3 to +4
<test name="TestHeterogeneousCoreSonicTritonRetryActionSame" command="cmsRun ${LOCALTOP}/src/HeterogeneousCore/SonicTriton/test/tritonTest_cfg.py --modules TritonGraphProducer --maxEvents 2 --unittest --device cpu --retryAction same"/>
<test name="TestHeterogeneousCoreSonicTritonRetryActionDiff" command="cmsRun ${LOCALTOP}/src/HeterogeneousCore/SonicTriton/test/tritonTest_cfg.py --modules TritonGraphProducer --maxEvents 2 --unittest --device cpu --retryAction diff"/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do these tests work without a driver script to enable/disable servers?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They will pass but they does not do what they suggest to test.
The retryDiff test will require some fiddling because the server choice is still undeterministic among remote servers.
I can commit a retry same script retry_action_same.sh for now.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in b9a4f8e

@kpedro88

Copy link
Copy Markdown

We will also have to update the various reco/miniaod algorithm configuration files that currently set allowedTries = cms.untracked.uint32(0)

@kakwok

kakwok commented Jul 14, 2026

Copy link
Copy Markdown
Author

Configs are updated as well Update allowedTries config

Comment on lines +109 to +121
action = cms.PSet(
retryType = cms.string('RetrySameServerAction'),
allowedTries = cms.untracked.uint32(options.tries))
if options.retryAction != 'same':
action.retryType = cms.string('RetryActionDiffServer')

fallback = cms.PSet(retryType = cms.string('RetryFallbackServerAction'))
return dict(
compression = cms.untracked.string(options.compression),
useSharedMemory = cms.untracked.bool(not options.noShm),
timeout = cms.untracked.uint32(options.timeout),
timeoutUnit = cms.untracked.string(options.timeoutUnit),
allowedTries = cms.untracked.uint32(options.tries),
Retry = cms.VPSet(action,fallback)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kpedro88 On the topic of configuration, should we add a RetryFallbackServerAction to all configurations as default?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants