io.zeebe.broker.system.SystemContext Maven / Gradle / Ivy
/*
* Zeebe Broker Core
* Copyright © 2017 camunda services GmbH ([email protected])
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package io.zeebe.broker.system;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.*;
import io.zeebe.broker.Broker;
import io.zeebe.broker.Loggers;
import io.zeebe.broker.system.threads.cfg.ThreadingCfg;
import io.zeebe.broker.transport.cfg.SocketBindingCfg;
import io.zeebe.broker.transport.cfg.TransportComponentCfg;
import io.zeebe.servicecontainer.ServiceContainer;
import io.zeebe.servicecontainer.impl.ServiceContainerImpl;
import io.zeebe.util.FileUtil;
import io.zeebe.util.metrics.MetricsManager;
import io.zeebe.util.sched.ActorScheduler;
import io.zeebe.util.sched.clock.ActorClock;
import io.zeebe.util.sched.future.ActorFuture;
import org.slf4j.Logger;
public class SystemContext implements AutoCloseable
{
private static final int MAX_THREAD_COUNT = Math.max(Runtime.getRuntime().availableProcessors() - 1, 1);
public static final Logger LOG = Loggers.SYSTEM_LOGGER;
public static final String BROKER_ID_LOG_PROPERTY = "broker-id";
public static final int CLOSE_TIMEOUT = 10;
protected final ServiceContainer serviceContainer;
protected final List components = new ArrayList<>();
protected final ConfigurationManager configurationManager;
protected final List> requiredStartActions = new ArrayList<>();
protected Map diagnosticContext;
protected final ActorScheduler scheduler;
private MetricsManager metricsManager;
public SystemContext(String configFileLocation, ActorClock clock)
{
this(new ConfigurationManagerImpl(configFileLocation), clock);
}
public SystemContext(InputStream configStream, ActorClock clock)
{
this(new ConfigurationManagerImpl(configStream), clock);
}
public SystemContext(ConfigurationManager configurationManager, ActorClock clock)
{
final String brokerId = readBrokerId(configurationManager);
this.diagnosticContext = Collections.singletonMap(BROKER_ID_LOG_PROPERTY, brokerId);
this.configurationManager = configurationManager;
// TODO: submit diagnosticContext to actor scheduler once supported
this.metricsManager = initMetricsManager(brokerId);
this.scheduler = initScheduler(clock, brokerId);
this.serviceContainer = new ServiceContainerImpl(this.scheduler);
this.scheduler.start();
initBrokerInfoMetric();
}
private MetricsManager initMetricsManager(String brokerId)
{
final Map globalLabels = new HashMap<>();
globalLabels.put("cluster", "zeebe");
globalLabels.put("node", brokerId);
return new MetricsManager("zb_", globalLabels);
}
private void initBrokerInfoMetric()
{
// one-shot metric to submit metadata
metricsManager.newMetric("broker_info")
.type("counter")
.label("version", Broker.VERSION)
.create()
.incrementOrdered();
}
private ActorScheduler initScheduler(ActorClock clock, String brokerId)
{
final ThreadingCfg cfg = configurationManager.readEntry("threading", ThreadingCfg.class);
int numberOfThreads = cfg.numberOfThreads;
if (numberOfThreads > MAX_THREAD_COUNT)
{
LOG.warn("Configured thread count {} is larger than MAX_THREAD_COUNT {}. Falling back max thread count.", numberOfThreads, MAX_THREAD_COUNT);
numberOfThreads = MAX_THREAD_COUNT;
}
else if (numberOfThreads < 1)
{
// use max threads by default
numberOfThreads = MAX_THREAD_COUNT;
}
final int ioBoundThreads = 2;
final int cpuBoundThreads = Math.max(1, numberOfThreads - ioBoundThreads);
Loggers.SYSTEM_LOGGER.info("Scheduler configuration: Threads{cpu-bound: {}, io-bound: {}}.", cpuBoundThreads, ioBoundThreads);
return ActorScheduler.newActorScheduler()
.setActorClock(clock)
.setMetricsManager(metricsManager)
.setCpuBoundActorThreadCount(cpuBoundThreads)
.setIoBoundActorThreadCount(ioBoundThreads)
.setSchedulerName(brokerId)
.build();
}
protected static String readBrokerId(ConfigurationManager configurationManager)
{
final TransportComponentCfg transportComponentCfg = configurationManager.readEntry("network", TransportComponentCfg.class);
final SocketBindingCfg clientApiCfg = transportComponentCfg.clientApi;
return clientApiCfg.getHost(transportComponentCfg.host) + ":" + clientApiCfg.getPort();
}
public ActorScheduler getScheduler()
{
return scheduler;
}
public ServiceContainer getServiceContainer()
{
return serviceContainer;
}
public void addComponent(Component component)
{
this.components.add(component);
}
public List getComponents()
{
return components;
}
public void init()
{
serviceContainer.start();
for (Component brokerComponent : components)
{
try
{
brokerComponent.init(this);
}
catch (RuntimeException e)
{
close();
throw e;
}
}
try
{
for (ActorFuture> requiredStartAction : requiredStartActions)
{
requiredStartAction.get(20, TimeUnit.SECONDS);
}
}
catch (Exception e)
{
LOG.error("Could not start broker", e);
close();
throw new RuntimeException(e);
}
}
@Override
public void close()
{
LOG.info("Closing...");
try
{
serviceContainer.close(CLOSE_TIMEOUT, TimeUnit.SECONDS);
}
catch (TimeoutException e)
{
LOG.error("Failed to close broker within {} seconds.", CLOSE_TIMEOUT, e);
}
catch (ExecutionException | InterruptedException e)
{
LOG.error("Exception while closing broker", e);
}
finally
{
try
{
scheduler.stop().get(CLOSE_TIMEOUT, TimeUnit.SECONDS);
}
catch (TimeoutException e)
{
LOG.error("Failed to close scheduler within {} seconds", CLOSE_TIMEOUT, e);
}
catch (ExecutionException | InterruptedException e)
{
LOG.error("Exception while closing scheduler", e);
}
finally
{
final GlobalConfiguration config = configurationManager.getGlobalConfiguration();
final String directory = config.getDirectory();
if (config.isTempDirectory())
{
try
{
FileUtil.deleteFolder(directory);
}
catch (IOException e)
{
LOG.error("Exception while deleting temp folder", e);
}
}
}
}
}
public ConfigurationManager getConfigurationManager()
{
return configurationManager;
}
public void addRequiredStartAction(ActorFuture> future)
{
requiredStartActions.add(future);
}
public Map getDiagnosticContext()
{
return diagnosticContext;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy