Principle:Vespa engine Vespa Subscriber Shutdown
| Metadata | |
|---|---|
| Sources | Vespa |
| Domains | Configuration, Distributed_Systems |
| Last Updated | 2026-02-09 12:00 GMT |
Overview
Subscriber shutdown gracefully terminates all configuration subscriptions, interrupting any pending blocking calls, unsubscribing all configs, and closing underlying transport connections to prevent resource leaks.
Description
The final phase of the config subscription lifecycle is shutdown. When a process no longer needs configuration updates -- whether due to normal termination, error recovery, or component lifecycle management -- it must properly shut down the config subscriber to release all associated resources.
Subscriber shutdown is responsible for:
Interrupting Blocking Calls: If a thread is currently blocked in nextConfig() or nextGeneration(), the close operation must wake it up immediately. This is accomplished by transitioning the subscription set state to CLOSED and signaling the condition variable. The blocked call then detects the closed state and returns false.
Unsubscribing All Configs: Each active subscription must be unregistered from the config manager. This tells the config manager to stop fetching updates for those subscriptions, freeing server-side resources (such as long-poll sessions).
Closing Subscriptions: Each ConfigSubscription is individually closed, which marks it as inactive and prevents further update processing. The subscription's source is released, which in the FRT case closes the underlying RPC connection.
Preventing Post-Close Operations: After close, any subsequent calls to nextConfig(), nextGeneration(), or subscribe() either return false or throw a ConfigRuntimeException. The isClosed() method allows callers to check the subscriber's state.
Destructor Safety: The ConfigSubscriptionSet destructor calls close(), ensuring that even if close is not called explicitly, resources are released when the subscriber goes out of scope. This follows the RAII (Resource Acquisition Is Initialization) pattern.
Usage
Use this principle when shutting down any Vespa process or component that has active config subscriptions. Proper shutdown is essential for:
- Clean process termination without resource leaks
- Graceful restart during hot-reconfiguration
- Thread safety when a control thread needs to stop a worker thread's config polling loop
- Error recovery when a component needs to be torn down and rebuilt
The typical shutdown pattern is:
- Signal the subscriber to close (from a control thread)
- The polling thread's
nextConfig()/nextGeneration()returnsfalse - The polling thread exits its loop
- The subscriber object is destroyed (final cleanup)
Theoretical Basis
Subscriber shutdown implements the graceful degradation pattern in distributed systems. Rather than abruptly severing connections, the shutdown sequence ensures:
Cooperative Cancellation: The close operation does not forcefully terminate threads. Instead, it sets a state flag and signals waiting threads, allowing them to exit their blocking calls gracefully. This follows the cooperative multitasking model:
- close() sets state to CLOSED and signals condition variable
- blocked thread wakes, checks state, and returns false
Resource Ordering: The shutdown sequence follows a strict ordering to prevent use-after-free and other lifecycle issues:
- State transition to
CLOSED(prevents new operations) - Condition variable notification (wakes blocked threads)
- Unsubscribe from config manager (releases server-side resources)
- Close each subscription (releases client-side resources)
This ordering ensures that:
- No new operations begin after the state transition
- Blocked threads are woken before resources are released
- Server-side resources are freed before client-side resources
RAII Guarantee: The destructor-based cleanup ensures the total cleanup property:
- For every resource acquired, there exists a guaranteed release path
This property holds even in the presence of exceptions, since C++ destructors run during stack unwinding.