/* * Copyright 2014 Avanza Bank AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.avanza.astrix.serviceunit; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import javax.annotation.PreDestroy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.avanza.astrix.beans.config.AstrixConfig; import com.avanza.astrix.beans.core.AstrixSettings; import com.avanza.astrix.beans.registry.AstrixServiceRegistryFactory; import com.avanza.astrix.beans.registry.ServiceRegistryExporterClient; import com.avanza.astrix.beans.service.ServiceProperties; import com.avanza.astrix.beans.util.AstrixFrameworkThread; import com.avanza.astrix.config.DynamicLongProperty; import com.avanza.astrix.core.ServiceUnavailableException; /** * The service registry worker is a server-side component responsible for continuously publishing * all exported services from the current application onto the service registry. * * @author Elias Lindholm (elilin) * */ public class ServiceRegistryExporterWorker extends AstrixFrameworkThread { private final List<ServiceRegistryExportedService> exportedServices = new CopyOnWriteArrayList<>(); private ServiceRegistryExporterClient serviceRegistryProviderClient; private final Logger log = LoggerFactory.getLogger(ServiceRegistryExporterWorker.class); private final DynamicLongProperty exportIntervallMillis; private final DynamicLongProperty serviceLeaseTimeMillis; private final DynamicLongProperty retryIntervallMillis; private final AstrixConfig config; private final Timer timer = new Timer(); private final AstrixServiceRegistryFactory serviceRegistryFactory; public ServiceRegistryExporterWorker(AstrixConfig config, AstrixServiceRegistryFactory serviceRegistryFactory) { super("ServiceRegistryExporter"); this.config = config; this.serviceRegistryFactory = serviceRegistryFactory; this.exportIntervallMillis = config.get(AstrixSettings.SERVICE_REGISTRY_EXPORT_INTERVAL); this.retryIntervallMillis = config.get(AstrixSettings.SERVICE_REGISTRY_EXPORT_RETRY_INTERVAL); this.serviceLeaseTimeMillis = config.get(AstrixSettings.SERVICE_REGISTRY_LEASE); } public void startServiceExporter() { if (exportedServices.isEmpty()) { log.info("No ServiceExporters configured. No services will be published to service registry"); return; } createServiceRegistryExporterClient(); start(); } private void createServiceRegistryExporterClient() { /* * The ServiceRegistryExporterClient is created lazily to * avoid that the service registry is attempting to create an * AstrixServiceRegistry instance against itself. */ String subsystem = config.get(AstrixSettings.SUBSYSTEM_NAME).get(); String applicationInstanceId = config.get(AstrixSettings.APPLICATION_INSTANCE_ID).get(); String applicationTag = config.get(AstrixSettings.APPLICATION_TAG).get(); String zone = subsystem; if (applicationTag != null) { zone = subsystem + "#" + applicationTag; } this.serviceRegistryProviderClient = new ServiceRegistryExporterClient(serviceRegistryFactory.createServiceRegistry(), subsystem, applicationInstanceId, zone); } @PreDestroy public void destroy() { interrupt(); } public void triggerServiceExport() { this.timer.wakeup(); } @Override public void run() { while (!interrupted()) { long sleepTimeUntilNextAttempt = this.exportIntervallMillis.get(); try { exportProvidedServcies(); } catch (ServiceUnavailableException e) { // Not bound to service registry sleepTimeUntilNextAttempt = this.retryIntervallMillis.get(); log.info(String.format("Failed to export services to registry. Sleeping %s millis until next attempt.", sleepTimeUntilNextAttempt), e); } catch (Exception e) { log.info(String.format("Failed to export services to registry. Sleeping %s millis until next attempt.", sleepTimeUntilNextAttempt), e); } try { this.timer.sleep(sleepTimeUntilNextAttempt); } catch (InterruptedException e) { interrupt(); } } log.info("ServiceRegistryExporterWorker is interrupted, won't publish to service registry anymore."); } private void exportProvidedServcies() { for (ServiceRegistryExportedService exportedService : exportedServices) { ServiceProperties serviceProperties = exportedService.exportServiceProperties(); serviceRegistryProviderClient.register(serviceProperties.getApi(), serviceProperties, serviceLeaseTimeMillis.get()); log.debug("Exported to service registry. service={} properties={}", serviceProperties.getApi().getName(), serviceProperties); } } public void addServiceBuilder( ServiceRegistryExportedService serviceRegistryExportedService) { this.exportedServices.add(serviceRegistryExportedService); } private static class Timer { private final Object monitor = new Object(); void sleep(long time) throws InterruptedException { synchronized (monitor) { monitor.wait(time); } } void wakeup() { synchronized (monitor) { monitor.notifyAll(); } } } }