use of org.apache.twill.common.Cancellable in project cdap by caskdata.
the class WebappProgramRunner method run.
@Override
public ProgramController run(Program program, ProgramOptions options) {
try {
ProgramType processorType = program.getType();
Preconditions.checkNotNull(processorType, "Missing processor type");
Preconditions.checkArgument(processorType == ProgramType.WEBAPP, "Only WEBAPP process type is supported");
LOG.info("Initializing Webapp for app {} with jar {}", program.getApplicationId(), program.getJarLocation().getName());
String serviceName = getServiceName(program.getId());
Preconditions.checkNotNull(serviceName, "Cannot determine service name for program %s", program.getName());
LOG.info("Got service name {}", serviceName);
// Start netty server
// TODO: add metrics reporting
JarHttpHandler jarHttpHandler = webappHttpHandlerFactory.createHandler(program.getJarLocation());
NettyHttpService.Builder builder = new CommonNettyHttpServiceBuilder(cConf, program.getId().toString());
builder.setHttpHandlers(jarHttpHandler);
builder.setUrlRewriter(new WebappURLRewriter(jarHttpHandler));
builder.setHost(hostname.getCanonicalHostName());
NettyHttpService httpService = builder.build();
httpService.start();
final InetSocketAddress address = httpService.getBindAddress();
RunId runId = ProgramRunners.getRunId(options);
// Register service, and the serving host names.
final List<Cancellable> cancellables = Lists.newArrayList();
LOG.info("Webapp {} running on address {} registering as {}", program.getApplicationId(), address, serviceName);
cancellables.add(serviceAnnouncer.announce(serviceName, address.getPort()));
for (String hname : getServingHostNames(Locations.newInputSupplier(program.getJarLocation()))) {
final String sname = ProgramType.WEBAPP.name().toLowerCase() + "/" + hname;
LOG.info("Webapp {} running on address {} registering as {}", program.getApplicationId(), address, sname);
cancellables.add(discoveryService.register(ResolvingDiscoverable.of(new Discoverable(sname, address))));
}
return new WebappProgramController(program.getId().run(runId), httpService, new Cancellable() {
@Override
public void cancel() {
for (Cancellable cancellable : cancellables) {
cancellable.cancel();
}
}
});
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
use of org.apache.twill.common.Cancellable in project cdap by caskdata.
the class AbstractHttpHandlerDelegator method wrapResponder.
/**
* Returns a new instance of {@link DelayedHttpServiceResponder} that wraps around the given {@link HttpResponder}
* object. This method is called from handler class generated by {@link HttpHandlerGenerator}.
*/
@SuppressWarnings("unused")
protected final DelayedHttpServiceResponder wrapResponder(HttpResponder responder) {
MetricsContext collector = this.metricsContext;
HttpServiceContext serviceContext = context.getServiceContext();
Preconditions.checkState(serviceContext instanceof TransactionalHttpServiceContext, "This instance of HttpServiceContext does not support transactions.");
if (serviceContext.getSpecification() != null) {
collector = metricsContext.childContext(Constants.Metrics.Tag.HANDLER, serviceContext.getSpecification().getName());
}
return new DelayedHttpServiceResponder(responder, new BodyProducerFactory() {
@Override
public BodyProducer create(HttpContentProducer contentProducer, TransactionalHttpServiceContext serviceContext) {
final ClassLoader programContextClassLoader = new CombineClassLoader(null, ImmutableList.of(contentProducer.getClass().getClassLoader(), getClass().getClassLoader()));
// Capture the context since we need to keep it until the end of the content producing.
// We don't need to worry about double capturing of the context when HttpContentConsumer is used.
// This is because when HttpContentConsumer is used, the responder constructed here will get closed and this
// BodyProducerFactory won't be used.
final Cancellable contextReleaser = context.capture();
return new BodyProducerAdapter(contentProducer, serviceContext, programContextClassLoader, contextReleaser);
}
}, (TransactionalHttpServiceContext) serviceContext, collector);
}
use of org.apache.twill.common.Cancellable in project cdap by caskdata.
the class AbstractHttpHandlerDelegator method wrapContentConsumer.
/**
* Returns a new instance of {@link BodyConsumer} that wraps around the given {@link HttpContentConsumer}
* and {@link DelayedHttpServiceResponder}.
*
* IMPORTANT: This method will also capture the context associated with the current thread, hence after
* this method is called, no other methods on this class should be called from the current thread.
*
* This method is called from handler class generated by {@link HttpHandlerGenerator}.
*/
@SuppressWarnings("unused")
protected final BodyConsumer wrapContentConsumer(HttpContentConsumer consumer, DelayedHttpServiceResponder responder) {
Preconditions.checkState(!responder.hasBufferedResponse(), "HttpContentConsumer may not be used after a response has already been sent.");
// Close the provided responder since a new one will be created for the BodyConsumerAdapter to use.
responder.close();
final HttpServiceContext serviceContext = context.getServiceContext();
Preconditions.checkState(serviceContext instanceof TransactionalHttpServiceContext, "This instance of HttpServiceContext does not support transactions.");
final Cancellable contextReleaser = context.capture();
final ClassLoader programContextClassLoader = new CombineClassLoader(null, ImmutableList.of(consumer.getClass().getClassLoader(), getClass().getClassLoader()));
return new BodyConsumerAdapter(new DelayedHttpServiceResponder(responder, new BodyProducerFactory() {
@Override
public BodyProducer create(HttpContentProducer contentProducer, TransactionalHttpServiceContext serviceContext) {
// Transfer the captured context from the content consumer to the content producer
return new BodyProducerAdapter(contentProducer, serviceContext, programContextClassLoader, contextReleaser);
}
}), consumer, serviceContext, programContextClassLoader, contextReleaser);
}
use of org.apache.twill.common.Cancellable in project cdap by caskdata.
the class SparkRuntimeUtils method initSparkMain.
/**
* Initialize a Spark main() method. This is the first method to be called from the main() method of any
* spark program.
*
* @return a {@link Cancellable} for releasing resources.
*/
public static Cancellable initSparkMain() {
final Thread mainThread = Thread.currentThread();
SparkClassLoader sparkClassLoader;
try {
sparkClassLoader = SparkClassLoader.findFromContext();
} catch (IllegalStateException e) {
sparkClassLoader = SparkClassLoader.create();
}
final ClassLoader oldClassLoader = ClassLoaders.setContextClassLoader(sparkClassLoader.getRuntimeContext().getProgramInvocationClassLoader());
final SparkExecutionContext sec = sparkClassLoader.getSparkExecutionContext(true);
final SparkRuntimeContext runtimeContext = sparkClassLoader.getRuntimeContext();
String executorServiceURI = System.getenv(CDAP_SPARK_EXECUTION_SERVICE_URI);
final Service driverService;
if (executorServiceURI != null) {
// Creates the SparkDriverService in distributed mode for heartbeating and tokens update
driverService = new SparkDriverService(URI.create(executorServiceURI), runtimeContext);
} else {
// In local mode, just create a no-op service for state transition.
driverService = new AbstractService() {
@Override
protected void doStart() {
notifyStarted();
}
@Override
protected void doStop() {
notifyStopped();
}
};
}
// Watch for stopping of the driver service.
// It can happen when a user program finished such that the Cancellable.cancel() returned by this method is called,
// or it can happen when it received a stop command (distributed mode) in the SparkDriverService via heartbeat.
// In local mode, the LocalSparkSubmitter calls the Cancellable.cancel() returned by this method directly
// (via SparkMainWraper).
// We use a service listener so that it can handle all cases.
final CountDownLatch mainThreadCallLatch = new CountDownLatch(1);
driverService.addListener(new ServiceListenerAdapter() {
@Override
public void terminated(Service.State from) {
handleStopped();
}
@Override
public void failed(Service.State from, Throwable failure) {
handleStopped();
}
private void handleStopped() {
// Avoid interrupt/join on the current thread
if (Thread.currentThread() != mainThread) {
mainThread.interrupt();
// If it is spark streaming, wait for the user class call returns from the main thread.
if (SparkRuntimeEnv.getStreamingContext().isDefined()) {
Uninterruptibles.awaitUninterruptibly(mainThreadCallLatch);
}
}
// Close the SparkExecutionContext (it will stop all the SparkContext and release all resources)
if (sec instanceof AutoCloseable) {
try {
((AutoCloseable) sec).close();
} catch (Exception e) {
// Just log. It shouldn't throw, and if it does (due to bug), nothing much can be done
LOG.warn("Exception raised when calling {}.close() for program run {}.", sec.getClass().getName(), runtimeContext.getProgramRunId(), e);
}
}
}
}, Threads.SAME_THREAD_EXECUTOR);
driverService.startAndWait();
return new Cancellable() {
@Override
public void cancel() {
// since it's the last thing that Spark main methhod would do.
if (Thread.currentThread() == mainThread) {
mainThreadCallLatch.countDown();
mainThread.setContextClassLoader(oldClassLoader);
}
driverService.stopAndWait();
}
};
}
use of org.apache.twill.common.Cancellable in project cdap by caskdata.
the class AuthenticationHandler method getAuthenticationURLs.
/**
* Gets a {@link JsonArray} of url strings to the authentication server instances.
*/
private JsonArray getAuthenticationURLs() {
// If the auth server urls are known via configuration, just use it
final JsonArray result = new JsonArray();
if (!authServerURLs.isEmpty()) {
for (String url : authServerURLs) {
result.add(new JsonPrimitive(url));
}
return result;
}
// Use service discovery to get URLs of the auth servers
final String protocol = getProtocol(cConf);
final int port = getPort(cConf);
ServiceDiscovered serviceDiscovered = discoveryServiceClient.discover(Constants.Service.EXTERNAL_AUTHENTICATION);
addAuthServerUrls(serviceDiscovered, protocol, port, result);
if (result.size() > 0) {
return result;
}
// For bootstrapping, the service discovery takes time to fill in the cache from ZK, hence use a callback
// and a timed future to get the result
final SettableFuture<JsonArray> future = SettableFuture.create();
Cancellable cancellable = serviceDiscovered.watchChanges(new ServiceDiscovered.ChangeListener() {
@Override
public void onChange(ServiceDiscovered serviceDiscovered) {
addAuthServerUrls(serviceDiscovered, protocol, port, result);
if (result.size() > 0) {
future.set(result);
}
}
}, Threads.SAME_THREAD_EXECUTOR);
try {
return future.get(2, TimeUnit.SECONDS);
} catch (TimeoutException e) {
LOG.warn("No authentication server detected via service discovery");
return result;
} catch (Exception e) {
// There shouldn't be other exception, hence just returning
return result;
} finally {
cancellable.cancel();
}
}
Aggregations