Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Implementation:Vespa engine Vespa ConfigSubscriber Close

From Leeroopedia


Field Value
Sources Vespa
Domains Configuration, Distributed_Systems
Type API Doc
Last Updated 2026-02-09 12:00 GMT

Overview

ConfigSubscriber::close gracefully terminates all configuration subscriptions, interrupting any pending blocking calls and releasing all associated resources.

Description

The close() method is the entry point for shutting down a config subscriber. It delegates to ConfigSubscriptionSet::close(), which performs the actual shutdown sequence:

  1. State transition: Under a mutex lock, sets the subscription set state to CLOSED and notifies the condition variable. This immediately unblocks any thread waiting in nextConfig() or nextGeneration().
  2. Unsubscribe: For each subscription in the subscription list, calls IConfigManager::unsubscribe() to deregister the subscription from the config manager. This stops the config manager from fetching updates for this subscription.
  3. Close subscriptions: Calls close() on each individual ConfigSubscription, which sets its closed flag and releases the underlying source.

The ConfigSubscriptionSet destructor also calls close(), providing RAII-style cleanup as a safety net.

After close, the following behavior is guaranteed:

  • isClosed() returns true
  • nextConfig() and nextGeneration() return false immediately
  • subscribe() throws ConfigRuntimeException

Code Reference

Source Location

Repository
vespa-engine/vespa
File (ConfigSubscriber declaration)
config/src/vespa/config/subscription/configsubscriber.h
Line
96
File (ConfigSubscriber definition)
config/src/vespa/config/subscription/configsubscriber.cpp
Lines
33--36
File (ConfigSubscriptionSet definition)
config/src/vespa/config/subscription/configsubscriptionset.cpp
Lines
113--124

ConfigSubscriber::close Signature

void ConfigSubscriber::close();

ConfigSubscriber::close Implementation

void
ConfigSubscriber::close()
{
    _set.close();
}

ConfigSubscriptionSet::close Implementation

void
ConfigSubscriptionSet::close()
{
    {
        std::lock_guard guard(_lock);
        _state = CLOSED;
        _cond.notify_all();
    }
    for (const auto & subscription : _subscriptionList) {
        _mgr.unsubscribe(*subscription);
        subscription->close();
    }
}

isClosed Check

bool ConfigSubscriber::isClosed() const {
    return _set.isClosed();
}

bool ConfigSubscriptionSet::isClosed() const noexcept {
    return (_state.load(std::memory_order_relaxed) == CLOSED);
}

I/O Contract

Inputs

The close() method takes no parameters.

Outputs

Name Type Description
return void No return value. The method completes when all subscriptions have been unsubscribed and closed.

Side Effects

  • Sets the subscription set state to CLOSED (atomic write with relaxed ordering)
  • Notifies the condition variable, waking any thread blocked in acquireSnapshot()
  • Unsubscribes all subscriptions from the config manager
  • Closes each individual ConfigSubscription
  • After return, the subscriber is permanently closed and cannot be reused

Thread Safety

The state transition and condition variable notification are performed under a mutex lock, making close() safe to call from a different thread than the one blocked in nextConfig()/nextGeneration(). This is the intended usage pattern: a control thread calls close() to signal a worker thread to stop its config polling loop.

State Machine

The subscription set follows this state machine:

OPEN --[nextConfig/nextGeneration]--> FROZEN --[acquireSnapshot succeeds]--> CONFIGURED
  |                                     |                                       |
  +-----[close()]----> CLOSED <---------+----------[close()]--------------------+

The CLOSED state is terminal. There is no way to reopen a closed subscriber; a new ConfigSubscriber must be created.

Usage Examples

Graceful Shutdown from Control Thread

#include <vespa/config/subscription/configsubscriber.h>
#include "config-myapp.h"
#include <thread>

using namespace config;

ConfigSubscriber subscriber;
auto handle = subscriber.subscribe<MyappConfig>("myapp/instance1");

// Worker thread runs the config polling loop
std::thread worker([&subscriber, &handle]() {
    subscriber.nextConfig();
    auto cfg = handle->getConfig();
    applyConfig(*cfg);

    while (!subscriber.isClosed()) {
        if (subscriber.nextConfig(60s)) {
            auto cfg = handle->getConfig();
            applyConfig(*cfg);
        }
    }
    // Thread exits cleanly when subscriber is closed
});

// ... later, from the control thread ...
subscriber.close();  // Interrupts nextConfig(), worker exits loop
worker.join();

RAII-Based Cleanup

void runWithConfig() {
    ConfigSubscriber subscriber;
    auto handle = subscriber.subscribe<MyappConfig>("myapp/instance1");
    subscriber.nextConfig();

    auto cfg = handle->getConfig();
    doWork(*cfg);

    // subscriber destructor calls close() automatically
    // All subscriptions are unsubscribed and resources released
}

Checking Closed State

if (subscriber.isClosed()) {
    LOG(info, "Subscriber has been closed, exiting config loop");
    return;
}

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment