private boolean sendBatch(String batchedEvents, IStorage storage) { // This is "" if we upload an empty file which we should just skip if (batchedEvents.equals("")) { removedStorages.add(storage); return true; } byte[] compressedBatchedEvents = compressor.compress(batchedEvents); // Write event string try { if (compressedBatchedEvents != null) { sender.sendEvent(compressedBatchedEvents, true); } else { sender.sendEvent(batchedEvents); } } catch (IOException e) { logger.error(TAG, "Cannot send event: " + e.getMessage()); int newPeriod = period * 2; if (newPeriod > SettingsStore.getCllSettingsAsInt(SettingsStore.Settings.MAXRETRYPERIOD)) { // The next scheduled drain is coming soon (~2.5 min so going higher exponentially won't // help) return false; } // If we don't remove these then on next call the drain method will end up creating a new // empty file by this name. storages.removeAll(removedStorages); EventQueueWriter r = new EventQueueWriter( endpoint, storages, clientTelemetry, cllEvents, logger, executorService, newPeriod); r.setSender(sender); future = executorService.schedule(r, newPeriod, TimeUnit.SECONDS); return false; // If we run into an error sending events we just return. This ensures we don't // lose events } return true; }
/** Sends a real time event by itself */ protected void sendRealTimeEvent(SerializedEvent singleEvent) { // Check to see if this single serialized event is greater than MAX_BUFFER_SIZE, if it is we // drop it. if (singleEvent.getSerializedData().length() > SettingsStore.getCllSettingsAsInt(SettingsStore.Settings.MAXEVENTSIZEINBYTES)) { return; } try { sender.sendEvent(singleEvent.getSerializedData()); } catch (IOException e) { // Edge case for real time events that try to send but don't have network. // In this case we need to write to disk // Force Normal latency so we don't keep looping back to here handler.log(singleEvent); logger.error(TAG, "Cannot send event"); } for (ICllEvents event : cllEvents) { event.sendComplete(); } }
/** Serializes, batches, and sends events */ protected void send() { // Ensure that the serialized event string is under MAXEVENTSIZEINBYTES. // If it is over MAXEVENTSIZEINBYTES then we should use 2 or more strings and send them for (IStorage storage : storages) { if (executorService.isShutdown()) { return; } List<String> events = storage.drain(); for (String event : events) { this.clientTelemetry.IncrementEventsQueuedForUpload(); // Check to see if this single serialized event is greater than MAX_BUFFER_SIZE, if it is we // drop it. if (event.length() > SettingsStore.getCllSettingsAsInt(SettingsStore.Settings.MAXEVENTSIZEINBYTES)) { // This could cause big problems if the host application decides to do a ton of processing // for each // dropped event. for (ICllEvents cllEvent : cllEvents) { cllEvent.eventDropped(event); } continue; } if (batcher.canAddToBatch(event)) { try { batcher.addEventToBatch(event); } catch (EventBatcher.BatchFullException e) { logger.error(TAG, "Could not add to batch"); } } else { // Full batch, send events String batchedEvents = batcher.getBatchedEvents(); try { batcher.addEventToBatch(event); } catch (EventBatcher.BatchFullException e) { logger.error(TAG, "Could not add to batch"); } boolean sendResult = sendBatch(batchedEvents, storage); if (sendResult == false) { storage.close(); return; } } } // Send remaining events that didn't fill a whole batch String batchedEvents = batcher.getBatchedEvents(); boolean sendResult = sendBatch(batchedEvents, storage); if (sendResult == false) { storage.close(); return; } storage.discard(); } logger.info(TAG, "Sent " + clientTelemetry.snapshot.getEventsQueuedForUpload() + " events."); for (ICllEvents event : cllEvents) { event.sendComplete(); } }