JasperFx.Events 2.30.1, hit while debugging JasperFx/wolverine#3519 (agent fails to start on a multi-store Marten host with Wolverine-managed distribution).
The public StartAgentAsync masks the real failure reason
JasperFxAsyncDaemon<TOperations,TQuerySession>.StartAgentAsync(ShardName, CancellationToken):
public async Task<ISubscriptionAgent> StartAgentAsync(ShardName name, CancellationToken token)
{
await StartAgentAsync(name.Identity, token);
if (_agents.TryFind(name.Identity, out var agent)) return agent;
// Should not ever happen, but real life man
throw new Exception("Unable to start a subscription agent for " + name);
}
When the start fails, the caller (e.g. Wolverine's EventSubscriptionAgent.StartAsync) gets only System.Exception: Unable to start a subscription agent for Identity: X:All — with no cause attached.
The information exists but is dropped along the way:
startContinuousShardAsync returns bool and the exact-identity branch of the string overload ignores the return value (await startContinuousShardAsync(shard); return;), so a failed start falls through to the generic throw with nothing to say.
- The
false paths themselves are uneven: tryStartAgentAsync's catch logs the exception at Error level (good), but the side-effect-version-gate failure and the idempotent path return false silently — and in our production repro no Error log appeared at all, so whichever path failed was one of the silent ones. We burned the whole diagnosis on "which invisible branch was it."
Ask
- Make
startContinuousShardAsync (or the paths under it) carry the failure reason out — return a result object or stash the last-start-failure per shard — and include it in the wrapper's exception (throw new …("Unable to start …", lastFailure)).
- Log every
false path at Warning+ with the shard identity, including the gate skip and the idempotent-already-running case (Debug is fine for that one).
- Since callers like Wolverine retry every 30s forever, an unchanged generic exception means the operator's log fills with identical stacks that never explain themselves.
JasperFx.Events 2.30.1, hit while debugging JasperFx/wolverine#3519 (agent fails to start on a multi-store Marten host with Wolverine-managed distribution).
The public StartAgentAsync masks the real failure reason
JasperFxAsyncDaemon<TOperations,TQuerySession>.StartAgentAsync(ShardName, CancellationToken):When the start fails, the caller (e.g. Wolverine's
EventSubscriptionAgent.StartAsync) gets onlySystem.Exception: Unable to start a subscription agent for Identity: X:All— with no cause attached.The information exists but is dropped along the way:
startContinuousShardAsyncreturnsbooland the exact-identity branch of the string overload ignores the return value (await startContinuousShardAsync(shard); return;), so a failed start falls through to the generic throw with nothing to say.falsepaths themselves are uneven:tryStartAgentAsync's catch logs the exception at Error level (good), but the side-effect-version-gate failure and the idempotent path returnfalsesilently — and in our production repro no Error log appeared at all, so whichever path failed was one of the silent ones. We burned the whole diagnosis on "which invisible branch was it."Ask
startContinuousShardAsync(or the paths under it) carry the failure reason out — return a result object or stash the last-start-failure per shard — and include it in the wrapper's exception (throw new …("Unable to start …", lastFailure)).falsepath at Warning+ with the shard identity, including the gate skip and the idempotent-already-running case (Debug is fine for that one).