class IpcSenderService extends MonitoredProcess {

  synchronized public void add(InternalEvent ievent) throws TransportException {
    // Since threads are running concurrently, we need to check this proactively.
    // Even though handler just logs the exception, we're able to avoid starting new
    // multi part uploads and let the handler error out faster so it can re-try the payload.
    // We leave the value as is so it can be used during flush() to throw an exception.
    if (this.hasUnrecoverableException.get()) {
      // TODO: confirm for the s3 case that clients will need a lifecycle policy
      //  that aborts incomplete uploads within a timeframe.
      throw new TransportException("TransportThread was unsuccessful when adding an event.");
    }

    /*
     * Get appropriate buffer for the event's partition values
     */
    LinkedHashMap<String, String> partitions = ievent.getPartitions();

    // TODO: not sure why I made buffers synchronized
    synchronized (buffers) {
      if (partitions == null) {
        partitions = new LinkedHashMap<String, String>(0);
      }

      if (!this.buffers.containsKey(partitions)) {
        partitions = new LinkedHashMap<String, String>(partitions);
        this.buffers.put(partitions, this.transportFactory.newTransportBuffer());
      }

      TransportBuffer buffer = this.buffers.get(partitions);

      /*
       * Attempt to add event. If IllegalStateException occurs the buffer is full and must be
       * flushed/sent.
       */
      try {
        buffer.add(ievent);
        return;
      } catch (IllegalStateException e) {
        send(buffer, partitions);
      } catch (IOException e) {
        throw new TransportException("Exception occurred while adding to buffer", e);
      }

      /*
       * Remove buffer associated with the partitions and create a new one.
       */
      this.buffers.remove(partitions);
      buffer = this.transportFactory.newTransportBuffer();
      partitions = new LinkedHashMap<String, String>(partitions);
      this.buffers.put(partitions, buffer);

      /*
       * Finally add the event now that the buffer is empty
       */
      try {
        buffer.add(ievent);
      } catch (IllegalStateException e) {
        throw new TransportException("Buffer is full despite being newly created", e);
      } catch (IOException e) {
        throw new TransportException("Exception ocurred while adding to buffer", e);
      }
    }
  }

  public  IpcSenderService(TransportFactory factory);

}