The jDisc container provides the runtime environment for Vespa components
The jDisc container is Vespa’s powerful runtime environment that hosts application components. It provides dependency injection, lifecycle management, and a flexible component model for building search and document processing applications.
The container is immutable once created. Each reconfiguration produces a new container instance:
public interface Container extends SharedResource, Timer { /** * Resolves a RequestHandler for the given request. * Returns null if no match is found. */ RequestHandler resolveHandler(Request request); /** * Gets an instance of the specified type from the container. * Use dependency injection instead when possible. */ <T> T getInstance(Class<T> type);}
Components in the jDisc container follow a well-defined lifecycle:
1
Construction
The container creates component instances using constructor injection. Dependencies are automatically resolved and injected.
2
In Service
Components handle requests from multiple threads in parallel. This phase lasts until the container is replaced during reconfiguration.
3
Deconstruction
When a new container is activated, the old container waits for all active requests to complete, then calls deconstruct() on components in reverse dependency order.
Applications implement the Application interface to control the container lifecycle:
public interface Application { /** * Called when the application starts. * Use this to activate the initial Container. */ void start(); /** * Called when the application is stopping. * No new containers can be activated after this. */ void stop(); /** * Called after stop() and all containers have terminated. * Use this to clean up resources. */ void destroy();}
import com.yahoo.jdisc.application.ContainerBuilder;import com.yahoo.jdisc.application.ContainerActivator;// Create a builderContainerBuilder builder = containerActivator.newContainerBuilder();// Configure the containerbuilder.serverBindings().bind("http://*/search/*", new SearchHandler());builder.clientBindings().bind("http://*/", new HttpClient());// Activate - this replaces the current containercontainerActivator.activateContainer(builder);
Container activation is a critical operation. The old container continues serving requests until all ongoing requests complete, then it’s deconstructed.
Immutable state - Prefer immutable data structures created in the constructor
Read-only access - Build data in constructor, access read-only afterwards
Synchronization - Only when absolutely necessary (impacts performance)
public class ThreadSafeSearcher extends Searcher { // Immutable - built in constructor, safe for concurrent access private final Map<String, String> lookupTable; public ThreadSafeSearcher(SomeConfig config) { // Build immutable structures during construction Map<String, String> temp = new HashMap<>(); for (var entry : config.entries()) { temp.put(entry.key(), entry.value()); } this.lookupTable = Collections.unmodifiableMap(temp); } @Override public Result search(Query query, Execution execution) { // Safe concurrent read-only access String value = lookupTable.get(query.properties().getString("key")); return execution.search(query); }}