Esempio n. 1
0
        /// <summary>
        /// Dispatches a packet
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="cancellationToken"></param>
        /// <remarks>
        /// This dispatcher is fault tolerant to:
        /// 1. Null packets
        /// 2. Packets with no associated handlers
        /// 3. Packets which cannot be handled by their registered handlers
        ///
        /// This dispatcher is thread-safe as long as the loggers and handlers are thread-safe.
        /// We use correlation ids when we emit errors to match our packet log with our
        /// general log stream.
        ///
        /// This sample includes a "bug" on packets of a ID 5 to illustrate how exceptions
        /// in the dispatcher itself are handled by the caller.
        /// </remarks>
        public async Task DispatchAsync(IPacket packet, CancellationToken cancellationToken)
        {
            if (packet == null)
            {
                throw new ArgumentNullException(nameof(packet));
            }

            if (packet.Id == 5)
            {
                throw new Exception("Oh noes, a bug in the dispatcher!");
            }

            if (_handlers.TryGetValue(packet.Id, out var handler))
            {
                try
                {
                    await handler.ProcessPacketAsync(packet, cancellationToken);
                }
                catch (Exception ex)
                {
                    Guid correlationId = Guid.NewGuid();
                    _logger.Error(ex,
                                  "CID:{correlationId} Failed handling packet with id {packetId} and type {packetType}",
                                  correlationId.ToString(),
                                  packet.Id,
                                  packet.GetType().Name);
                    _packetLogger.LogPacket(PacketLogReason.Error, correlationId, packet);
                }
            }
            else
            {
                // Non-existent handler case
                Guid correlationId = Guid.NewGuid();
                _logger.Error(
                    "CID:{correlationId} Unexpected packet with id {packetId} and type {packetType}",
                    correlationId.ToString(),
                    packet.Id,
                    packet.GetType().Name);
                _packetLogger.LogPacket(PacketLogReason.Error, correlationId, packet);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// The main packet processing loop.
        /// </summary>
        /// <remarks>
        /// This method illustrates how the dispatcher can be used. For this illustration
        /// we use an async foreach, to simulate a thread which receives and processes packets
        /// independent of the rest of the process, and which responds to cancellation tokens
        /// by terminating any outstanding dispatches and terminating the waits on any
        /// incoming packets.
        /// </remarks>
        static async Task ProcessPacketsAsync(
            IPacketDispatcher dispatcher,
            IPacketLogger packetLogger,
            CancellationToken cancellationToken)
        {
            await foreach (var packet in GeneratePacketsAsync(cancellationToken))
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                try
                {
                    await dispatcher.DispatchAsync(packet, cancellationToken);
                }
                catch (Exception ex)
                {
                    Guid correlationId = Guid.NewGuid();
                    Log.Error(ex, "CID:{correlationId}: Exception invoking dispatcher for packet with id {id} and type {type}", correlationId, packet?.Id, packet?.GetType().Name);
                    packetLogger.LogPacket(PacketLogReason.Error, correlationId, packet);
                }
            }
        }