All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.sentry.appengine.connection.AppEngineAsyncConnection Maven / Gradle / Ivy

The newest version!
package io.sentry.appengine.connection;

import io.sentry.connection.EventSendCallback;
import com.google.appengine.api.taskqueue.DeferredTask;
import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import io.sentry.connection.Connection;
import io.sentry.environment.SentryEnvironment;
import io.sentry.event.Event;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import static com.google.appengine.api.taskqueue.DeferredTaskContext.setDoNotRetry;
import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withPayload;

/**
 * Asynchronous connections that can be used within Google App Engine.
 * 

* Instead of synchronously sending each event, use a the App Engine queue system to establish the connection * and send the event. *

* Google App Engine serialises the tasks before queuing them, to keep a link between the task and the * {@link AppEngineAsyncConnection} associated, a register of the instances of {@code AppEngineAsyncConnection} is * kept in {@link #APP_ENGINE_ASYNC_CONNECTIONS}.
* This register is populated when a new instance of {@code AppEngineAsyncConnection} is created and the connection * is removed from the register when it has been closed with {@link #close()}.
* The register works based on identifier defined by the user. There is no ID conflict handling, the user is expected * to manage the uniqueness of those ID. */ public class AppEngineAsyncConnection implements Connection { private static final Logger logger = LoggerFactory.getLogger(AppEngineAsyncConnection.class); // visible for testing static final Map APP_ENGINE_ASYNC_CONNECTIONS = new HashMap<>(); /** * Identifier of the async connection. */ private final String id; /** * Connection used to actually send the events. */ private final Connection actualConnection; /** * Queue used to send deferred tasks. */ private Queue queue = QueueFactory.getDefaultQueue(); /** * Boolean used to check whether the connection is still open or not. */ private boolean closed; /** * Creates a connection which will rely on an executor to send events. *

* Will propagate the {@link #close()} operation. * * @param id Identifier of the connection shared across all the instances of the application. * @param actualConnection Connection used to send the events. */ public AppEngineAsyncConnection(String id, Connection actualConnection) { this.actualConnection = actualConnection; this.id = id; APP_ENGINE_ASYNC_CONNECTIONS.put(id, this); } /** * {@inheritDoc} *

* The event will be added to a queue and will be handled by a separate {@code Thread} later on. */ @Override public void send(Event event) { if (!closed) { queue.add(withPayload(new EventSubmitter(id, event))); } } @Override public void addEventSendCallback(EventSendCallback eventSendCallback) { actualConnection.addEventSendCallback(eventSendCallback); } /** * {@inheritDoc}. *

* Closing the {@link AppEngineAsyncConnection} will gracefully remove every task created earlier from the queue. */ @Override public void close() throws IOException { logger.debug("Gracefully stopping Sentry tasks."); closed = true; actualConnection.close(); APP_ENGINE_ASYNC_CONNECTIONS.remove(id); } /** * Set the queue used to send EventSubmitter tasks. * * @param queueName name of the queue to use. */ public void setQueue(String queueName) { this.queue = QueueFactory.getQueue(queueName); } /** * Gets the queue that the events are sent to. * @return the App Engine Queue used by this connection */ public String getQueue() { return queue == null ? null : queue.getQueueName(); } /** * Simple DeferredTask using the {@link #send(Event)} method of the {@link #actualConnection}. */ // visible for testing static final class EventSubmitter implements DeferredTask { private final String connectionId; private final Event event; private EventSubmitter(String connectionId, Event event) { this.connectionId = connectionId; this.event = event; } // visible for testing String getConnectionId() { return connectionId; } // visible for testing Event getEvent() { return event; } @Override public void run() { setDoNotRetry(true); SentryEnvironment.startManagingThread(); try { // The current thread is managed by sentry AppEngineAsyncConnection connection = APP_ENGINE_ASYNC_CONNECTIONS.get(connectionId); if (connection == null) { logger.warn("Couldn't find the AppEngineAsyncConnection identified by '{}'. " + "The connection has probably been closed.", connectionId); return; } connection.actualConnection.send(event); } catch (RuntimeException e) { logger.error("An exception occurred while sending the event to Sentry.", e); } finally { SentryEnvironment.stopManagingThread(); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy