diff --git a/PushSharp.Apple/ApnsConnection.cs b/PushSharp.Apple/ApnsConnection.cs index 0908b166..856d462e 100644 --- a/PushSharp.Apple/ApnsConnection.cs +++ b/PushSharp.Apple/ApnsConnection.cs @@ -85,6 +85,10 @@ public void Send (CompletableApnsNotification notification) notifications.Enqueue (notification); + var currentIsSendBatchRunning = Interlocked.CompareExchange(ref isSendBatchRunning, 0, 0); + if (currentIsSendBatchRunning == 1) + return; + if (notifications.Count >= Configuration.InternalBatchSize) { // Make the timer fire immediately and send a batch off @@ -104,75 +108,90 @@ public void Send (CompletableApnsNotification notification) long batchId = 0; + int isSendBatchRunning; + async Task SendBatch () { - batchId++; - if (batchId >= long.MaxValue) - batchId = 1; - - // Pause the timer - timerBatchWait.Change (Timeout.Infinite, Timeout.Infinite); - - if (notifications.Count <= 0) + var currentIsSendBatchRunning = Interlocked.CompareExchange(ref isSendBatchRunning, 1, 0); + if (currentIsSendBatchRunning == 1) return; - // Let's store the batch items to send internally - var toSend = new List (); + try + { + batchId++; + if (batchId >= long.MaxValue) + batchId = 1; - while (notifications.Count > 0 && toSend.Count < Configuration.InternalBatchSize) { - var n = notifications.Dequeue (); - toSend.Add (n); - } + // Pause the timer + timerBatchWait.Change(Timeout.Infinite, Timeout.Infinite); + if (notifications.Count <= 0) + return; - Log.Info ("APNS-Client[{0}]: Sending Batch ID={1}, Count={2}", id, batchId, toSend.Count); + // Let's store the batch items to send internally + var toSend = new List(); - try { + lock (notificationBatchQueueLock) { + while (notifications.Count > 0 && toSend.Count < Configuration.InternalBatchSize) { + var n = notifications.Dequeue(); + toSend.Add(n); + } + } - var data = createBatch (toSend); - if (data != null && data.Length > 0) { + Log.Info("APNS-Client[{0}]: Sending Batch ID={1}, Count={2}", id, batchId, toSend.Count); - for (var i = 0; i <= Configuration.InternalBatchFailureRetryCount; i++) { + try { - await connectingSemaphore.WaitAsync (); + var data = createBatch(toSend); - try { - // See if we need to connect - if (!socketCanWrite () || i > 0) - await connect (); - } finally { - connectingSemaphore.Release (); - } - - try { - await networkStream.WriteAsync(data, 0, data.Length).ConfigureAwait(false); - break; - } catch (Exception ex) when (i != Configuration.InternalBatchFailureRetryCount) { - Log.Info("APNS-CLIENT[{0}]: Retrying Batch: Batch ID={1}, Error={2}", id, batchId, ex); + if (data != null && data.Length > 0) { + + for (var i = 0; i <= Configuration.InternalBatchFailureRetryCount; i++) + { + + await connectingSemaphore.WaitAsync(); + + try { + // See if we need to connect + if (!socketCanWrite() || i > 0) + await connect(); + } finally { + connectingSemaphore.Release(); + } + + try { + await networkStream.WriteAsync(data, 0, data.Length).ConfigureAwait(false); + break; + } catch (Exception ex) when (i != Configuration.InternalBatchFailureRetryCount) { + Log.Info("APNS-CLIENT[{0}]: Retrying Batch: Batch ID={1}, Error={2}", id, batchId, ex); + } } + + foreach (var n in toSend) + sent.Add(new SentNotification(n)); } + } catch (Exception ex) { + Log.Error("APNS-CLIENT[{0}]: Send Batch Error: Batch ID={1}, Error={2}", id, batchId, ex); foreach (var n in toSend) - sent.Add (new SentNotification (n)); + n.CompleteFailed(new ApnsNotificationException(ApnsNotificationErrorStatusCode.ConnectionError, + n.Notification, ex)); } - } catch (Exception ex) { - Log.Error ("APNS-CLIENT[{0}]: Send Batch Error: Batch ID={1}, Error={2}", id, batchId, ex); - foreach (var n in toSend) - n.CompleteFailed (new ApnsNotificationException (ApnsNotificationErrorStatusCode.ConnectionError, n.Notification, ex)); - } + Log.Info("APNS-Client[{0}]: Sent Batch, waiting for possible response...", id); - Log.Info ("APNS-Client[{0}]: Sent Batch, waiting for possible response...", id); + try { + await Reader(); + } catch (Exception ex) { + Log.Error("APNS-Client[{0}]: Reader Exception: {1}", id, ex); + } - try { - await Reader (); - } catch (Exception ex) { - Log.Error ("APNS-Client[{0}]: Reader Exception: {1}", id, ex); + Log.Info("APNS-Client[{0}]: Done Reading for Batch ID={1}, reseting batch timer...", id, batchId); + } finally { + Interlocked.Exchange(ref isSendBatchRunning, 0); } - Log.Info ("APNS-Client[{0}]: Done Reading for Batch ID={1}, reseting batch timer...", id, batchId); - // Restart the timer for the next batch timerBatchWait.Change (Configuration.InternalBatchingWaitPeriod, Timeout.InfiniteTimeSpan); } diff --git a/PushSharp.Core/Log.cs b/PushSharp.Core/Log.cs index fd749d2d..278b3452 100644 --- a/PushSharp.Core/Log.cs +++ b/PushSharp.Core/Log.cs @@ -24,12 +24,13 @@ public static class Log static List loggers { get; set; } static Dictionary counters; - static Log () + static Log() { - counters = new Dictionary (); - loggers = new List (); - - AddLogger (new ConsoleLogger ()); + counters = new Dictionary(); + loggers = new List(); +#if DEBUG + AddLogger(new DebugLogger()); +#endif } public static void AddLogger (ILogger logger) @@ -153,5 +154,31 @@ public void Write (LogLevel level, string msg, params object[] args) } } } + + public class DebugLogger : ILogger + { + public void Write(LogLevel level, string msg, params object[] args) + { + var s = msg; + + if (args != null && args.Length > 0) + s = string.Format(msg, args); + + var d = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ttt"); + + switch (level) + { + case LogLevel.Info: + System.Diagnostics.Debug.WriteLine(d + " [INFO] " + s); + break; + case LogLevel.Debug: + System.Diagnostics.Debug.WriteLine(d + " [DEBUG] " + s); + break; + case LogLevel.Error: + System.Diagnostics.Debug.WriteLine(d + " [ERROR] " + s); + break; + } + } + } }