WorkRequest
Internal readonly struct representing a unit of work queued for execution by a WorkRunner. Wraps a continuation callback and an optional ManualResetEvent for synchronous Send() operations. Exception-safe — catches and logs exceptions without crashing the runner queue.
Definition
Namespace: Paragon.Core.Async Assembly: Paragon.dll
internal readonly struct WorkRequestVisibility: internal — not directly accessible by game code.
Remarks
WorkRequest is the bridge between the SynchronizationContext.Post() / Send() calls and the actual callback execution. Two construction patterns exist:
Action-based — Used by the phase-specific
Post(Action, WorkExecutionTime)overload. TheActionis stored directly as the continuation.SendOrPostCallback-based — Used by the standard
Post(SendOrPostCallback, object)andSend(SendOrPostCallback, object)overrides. The callback and state are captured into a closure:() => delegateCallback.Invoke(state).
Error Handling
Invoke() wraps execution in a try/catch/finally block:
try — Calls
continuation.Invoke()catch — Catches any
Exceptionand logs it viaDebug.LogException()— the runner continues processing subsequent work requestsfinally — Signals the
ManualResetEvent(if present), unblocking any thread waiting on a synchronousSend()
This design ensures that a single failing continuation does not prevent the remaining queued work from executing.
Constructors
WorkRequest(Action, ManualResetEvent)
Creates a work request from a direct Action callback.
continuation
Action
(required)
Callback to execute
waitHandle
ManualResetEvent
null
Optional handle to signal on completion (used by Send())
WorkRequest(SendOrPostCallback, object, ManualResetEvent)
Creates a work request from a SendOrPostCallback and state. Captures both into a closure.
delegateCallback
SendOrPostCallback
(required)
Standard SynchronizationContext callback
state
object
(required)
State object passed to the callback
waitHandle
ManualResetEvent
null
Optional handle to signal on completion
Methods
Invoke
Executes the continuation, catches and logs any exceptions, and signals the wait handle (if present).
Behavior:
Calls
continuation.Invoke()If an exception occurs, logs it via
Debug.LogException(exception)— does not rethrowIn
finally, callswaitHandle?.Set()to unblock any waiting thread
Common Pitfalls
Exceptions are swallowed Invoke() catches all exceptions and logs them but does not rethrow. If a continuation throws, subsequent continuations in the same runner still execute. This is intentional — but it means exceptions in async continuations will only appear in the console log, not as unhandled exceptions.
Closure allocation The SendOrPostCallback constructor creates a closure (() => delegateCallback.Invoke(state)), which allocates. The Action constructor avoids this by storing the delegate directly. Hot-path code should prefer the Action overload where possible.
See Also
ParagonSynchronizationContext — creates and enqueues work requests
WorkExecutionTime — determines which runner a request is routed to
SynchronizationContext System — system overview
Last updated