/// <summary>
        /// Context-preserving variant of <see cref="FlowOperations.Where{TIn,TOut,TMat}"/>
        /// </summary>
        public static FlowWithContext <TCtx, TIn, TCtx, TOut, TMat> Where <TCtx, TIn, TOut, TMat>(
            this FlowWithContext <TCtx, TIn, TCtx, TOut, TMat> flow, Func <TOut, bool> predicate)
        {
            var stage = new Where <(TOut, TCtx)>(x => predicate(x.Item1));

            return(flow.Via(Flow.FromGraph(stage)));
        }
        /// <summary>
        /// Context-preserving variant of <see cref="FlowOperations.Select{T,TIn,TOut,TMat}"/>
        /// </summary>
        public static FlowWithContext <TCtx, TIn, TCtx, TOut2, TMat> Select <TCtx, TIn, TOut, TOut2, TMat>(
            this FlowWithContext <TCtx, TIn, TCtx, TOut, TMat> flow, Func <TOut, TOut2> fn)
        {
            var stage = new Select <(TOut, TCtx), (TOut2, TCtx)>(x => (fn(x.Item1), x.Item2));

            return(flow.Via(Flow.FromGraph(stage)));
        }
        /// <summary>
        /// Context-preserving variant of <see cref="FlowOperations.SelectAsync{T,TIn,TOut,TMat}"/>
        /// </summary>
        public static FlowWithContext <TCtx, TIn, TCtx, TOut2, TMat> SelectAsync <TCtx, TIn, TOut, TOut2, TMat>(
            this FlowWithContext <TCtx, TIn, TCtx, TOut, TMat> flow, int parallelism, Func <TOut, Task <TOut2> > fn)
        {
            var stage = new SelectAsync <(TOut, TCtx), (TOut2, TCtx)>(parallelism,
                                                                      async x => (await fn(x.Item1), x.Item2));

            return(flow.Via(Flow.FromGraph(stage)));
        }
        /// <summary>
        /// Apply the given function to each context element (leaving the data elements unchanged).
        /// </summary>
        public static SourceWithContext <TCtx2, TOut, TMat> SelectContext <TCtx, TCtx2, TOut, TMat>(
            this SourceWithContext <TCtx, TOut, TMat> flow, Func <TCtx, TCtx2> mapContext)
        {
            var stage = new Select <(TOut, TCtx), (TOut, TCtx2)>(x =>
                                                                 (x.Item1, mapContext(x.Item2)));

            return(flow.Via(Flow.FromGraph(stage)));
        }
        /// <summary>
        /// Context-preserving variant of <see cref="FlowOperations.Collect{T,TIn,TOut,TMat}"/>
        /// </summary>
        public static FlowWithContext <TCtx, TIn, TCtx, TOut2, TMat> Collect <TCtx, TIn, TOut, TOut2, TMat>(
            this FlowWithContext <TCtx, TIn, TCtx, TOut, TMat> flow, Func <TOut, TOut2> fn) where TOut2 : class
        {
            var stage = new Collect <(TOut, TCtx), (TOut2, TCtx)>(func: x =>
            {
                var result = fn(x.Item1);
                return(ReferenceEquals(result, null) ? default((TOut2, TCtx)) : (result, x.Item2));
            });

            return(flow.Via(Flow.FromGraph(stage)));
        }
Пример #6
0
        /// <summary>
        /// Transform this <see cref="Flow{TIn,TOut,TMat}"/> by appending the given processing steps.
        /// The <paramref name="combine"/> function is used to compose the materialized values of this flow and that
        /// flow into the materialized value of the resulting Flow.
        /// </summary>
        public Flow <TIn, TOut2, TMat3> ViaMaterialized <TOut2, TMat2, TMat3>(IGraph <FlowShape <TOut, TOut2>, TMat2> flow, Func <TMat, TMat2, TMat3> combine)
        {
            if (IsIdentity)
            {
                return(Flow.FromGraph((IGraph <FlowShape <TIn, TOut2>, TMat2>)flow)
                       .MapMaterializedValue(mat2 => combine(default(TMat), mat2)));
            }

            var copy = flow.Module.CarbonCopy();

            return(new Flow <TIn, TOut2, TMat3>(Module
                                                .Fuse(copy, Shape.Outlet, copy.Shape.Inlets.First(), combine)
                                                .ReplaceShape(new FlowShape <TIn, TOut2>(Shape.Inlet, (Outlet <TOut2>)copy.Shape.Outlets.First()))));
        }
        /// <summary>
        /// Context-preserving variant of <see cref="SourceOperations.StatefulSelectMany{T,TOut,TMat}"/>.
        /// </summary>
        public static SourceWithContext <TCtx, TOut2, TMat> StatefulSelectConcat <TCtx, TOut, TOut2, TMat>(
            this SourceWithContext <TCtx, TOut, TMat> flow, Func <Func <TOut, IEnumerable <TOut2> > > fn)
        {
            var stage = new StatefulSelectMany <(TOut, TCtx), (TOut2, TCtx)>(() =>
            {
                var fun = fn();
                return(itemWithContext =>
                {
                    var items = fun(itemWithContext.Item1);
                    return items.Select(i => (i, itemWithContext.Item2));
                });
            });

            return(flow.Via(Flow.FromGraph(stage)));
        }
Пример #8
0
        /// <summary>
        /// Creates a <see cref="Tcp.OutgoingConnection"/> instance representing a prospective TCP client connection to the given endpoint.
        /// <para>
        /// Note that the <see cref="ByteString"/> chunk boundaries are not retained across the network,
        /// to achieve application level chunks you have to introduce explicit framing in your streams,
        /// for example using the <see cref="Framing"/> stages.
        /// </para>
        /// </summary>
        /// <param name="remoteAddress"> The remote address to connect to</param>
        /// <param name="localAddress">Optional local address for the connection</param>
        /// <param name="options">TCP options for the connections, see <see cref="Akka.IO.Tcp"/> for details</param>
        /// <param name="halfClose"> Controls whether the connection is kept open even after writing has been completed to the accepted TCP connections.
        /// If set to true, the connection will implement the TCP half-close mechanism, allowing the server to
        /// write to the connection even after the client has finished writing.The TCP socket is only closed
        /// after both the client and server finished writing. This setting is recommended for clients and therefore it is the default setting.
        /// If set to false, the connection will immediately closed once the client closes its write side,
        /// independently whether the server is still attempting to write.
        /// </param>
        /// <param name="connectionTimeout">TBD</param>
        /// <param name="idleTimeout">TBD</param>
        /// <returns>TBD</returns>
        public Flow <ByteString, ByteString, Task <Tcp.OutgoingConnection> > OutgoingConnection(EndPoint remoteAddress, EndPoint localAddress = null,
                                                                                                IImmutableList <Inet.SocketOption> options    = null, bool halfClose = true, TimeSpan?connectionTimeout = null, TimeSpan?idleTimeout = null)
        {
            //connectionTimeout = connectionTimeout ?? TimeSpan.FromMinutes(60);

            var tcpFlow =
                Flow.FromGraph(new OutgoingConnectionStage(_system.Tcp(), remoteAddress, localAddress, options,
                                                           halfClose, connectionTimeout)).Via(new Detacher <ByteString>());

            if (idleTimeout.HasValue)
            {
                return(tcpFlow.Join(BidiFlow.BidirectionalIdleTimeout <ByteString, ByteString>(idleTimeout.Value)));
            }

            return(tcpFlow);
        }
        /// <summary>
        /// Context-preserving variant of <see cref="SourceOperations.Sliding{TOut,TMat}"/>
        /// Each output group will be associated with a `Seq` of corresponding context elements.
        /// </summary>
        public static SourceWithContext <IReadOnlyList <TCtx>, IReadOnlyList <TOut>, TMat> Sliding <TCtx, TOut, TMat>(
            this SourceWithContext <TCtx, TOut, TMat> flow, int n, int step = 1)
        {
            var stage = new Sliding <(TOut, TCtx)>(n, step);

            return(flow.Via(Flow.FromGraph(stage).Select(itemsWithContexts =>
            {
                var items = new List <TOut>(n);
                var ctxs = new List <TCtx>(n);

                foreach (var tuple in itemsWithContexts)
                {
                    items.Add(tuple.Item1);
                    ctxs.Add(tuple.Item2);
                }

                return ((IReadOnlyList <TOut>)items, (IReadOnlyList <TCtx>)ctxs);
            })));
        }
        /// <summary>
        /// Context-preserving variant of <see cref="FlowOperations.Grouped{TIn,TOut,TMat}"/>
        /// Each output group will be associated with a `Seq` of corresponding context elements.
        /// </summary>
        public static FlowWithContext <TCtx, TIn, IReadOnlyList <TCtx>, IReadOnlyList <TOut>, TMat> Grouped <TCtx, TIn,
                                                                                                             TOut, TMat>(
            this FlowWithContext <TCtx, TIn, TCtx, TOut, TMat> flow, int n)
        {
            var stage = new Grouped <(TOut, TCtx)>(n);

            return(flow.Via(Flow.FromGraph(stage).Select(itemsWithContexts =>
            {
                var items = new List <TOut>(n);
                var ctxs = new List <TCtx>(n);

                foreach (var tuple in itemsWithContexts)
                {
                    items.Add(tuple.Item1);
                    ctxs.Add(tuple.Item2);
                }

                return ((IReadOnlyList <TOut>)items, (IReadOnlyList <TCtx>)ctxs);
            })));
        }
Пример #11
0
 /// <summary>
 /// Wrap the given <see cref="Flow"/> with a <see cref="Flow"/> that will restart it when it fails using an exponential
 /// backoff. Notice that this <see cref="Flow"/> will not restart on completion of the wrapped flow.
 /// This <see cref="Flow"/> will not emit any failure
 /// The failures by the wrapped <see cref="Flow"/> will be handled by
 /// restarting the wrapping <see cref="Flow"/> as long as maxRestarts is not reached.
 /// Any termination signals sent to this <see cref="Flow"/> however will terminate the wrapped <see cref="Flow"/>, if it's
 /// running, and then the <see cref="Flow"/> will be allowed to terminate without being restarted.
 /// The restart process is inherently lossy, since there is no coordination between cancelling and the sending of
 /// messages. A termination signal from either end of the wrapped <see cref="Flow"/> will cause the other end to be terminated,
 /// nd any in transit messages will be lost. During backoff, this <see cref="Flow"/> will backpressure.
 /// This uses the same exponential backoff algorithm as <see cref="Akka.Pattern.Backoff"/>.
 /// </summary>
 /// <param name="flowFactory">A factory for producing the <see cref="Flow"/>] to wrap.</param>
 /// <param name="minBackoff">Minimum (initial) duration until the child actor will started again, if it is terminated</param>
 /// <param name="maxBackoff">The exponential back-off is capped to this duration</param>
 /// <param name="randomFactor">After calculation of the exponential back-off an additional random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay. In order to skip this additional delay pass in `0`.</param>
 /// <param name="maxRestarts">The amount of restarts is capped to this amount within a time frame of minBackoff. Passing `0` will cause no restarts and a negative number will not cap the amount of restarts.</param>
 public static Flow <TIn, TOut, NotUsed> OnFailuresWithBackoff <TIn, TOut, TMat>(Func <Flow <TIn, TOut, TMat> > flowFactory, TimeSpan minBackoff, TimeSpan maxBackoff, double randomFactor, int maxRestarts)
 => Flow.FromGraph(new RestartWithBackoffFlow <TIn, TOut, TMat>(flowFactory, minBackoff, maxBackoff, randomFactor, true, maxRestarts));
Пример #12
0
 /// <summary>
 /// Wrap the given <see cref="Flow"/> with a <see cref="Flow"/> that will restart it when it fails or complete using an exponential
 /// backoff.
 /// This <see cref="Flow"/> will not cancel, complete or emit a failure, until the opposite end of it has been cancelled or
 /// completed.Any termination by the <see cref="Flow"/> before that time will be handled by restarting it. Any termination
 /// signals sent to this <see cref="Flow"/> however will terminate the wrapped <see cref="Flow"/>, if it's running, and then the <see cref="Flow"/>
 /// will be allowed to terminate without being restarted.
 /// The restart process is inherently lossy, since there is no coordination between cancelling and the sending of
 /// messages. A termination signal from either end of the wrapped <see cref="Flow"/> will cause the other end to be terminated,
 /// and any in transit messages will be lost. During backoff, this <see cref="Flow"/> will backpressure.
 /// This uses the same exponential backoff algorithm as <see cref="Akka.Pattern.Backoff"/>.
 /// </summary>
 /// <param name="flowFactory">A factory for producing the <see cref="Flow"/>] to wrap.</param>
 /// <param name="minBackoff">Minimum (initial) duration until the child actor will started again, if it is terminated</param>
 /// <param name="maxBackoff">The exponential back-off is capped to this duration</param>
 /// <param name="randomFactor">After calculation of the exponential back-off an additional random delay based on this factor is added, e.g. `0.2` adds up to `20%` delay. In order to skip this additional delay pass in `0`.</param>
 public static Flow <TIn, TOut, NotUsed> WithBackoff <TIn, TOut, TMat>(Func <Flow <TIn, TOut, TMat> > flowFactory, TimeSpan minBackoff, TimeSpan maxBackoff, double randomFactor)
 => Flow.FromGraph(new RestartWithBackoffFlow <TIn, TOut, TMat>(flowFactory, minBackoff, maxBackoff, randomFactor, false, int.MaxValue));
Пример #13
0
 /// <summary>
 /// Wrap the given <see cref="Flow"/> with a <see cref="Flow"/> that will restart it when it fails or complete using an exponential
 /// backoff.
 /// <para>
 /// This <see cref="Flow"/> will not cancel, complete or emit a failure, until the opposite end of it has been cancelled or
 /// completed.Any termination by the <see cref="Flow"/> before that time will be handled by restarting it. Any termination
 /// signals sent to this <see cref="Flow"/> however will terminate the wrapped <see cref="Flow"/>, if it's running, and then the <see cref="Flow"/>
 /// will be allowed to terminate without being restarted.
 /// The restart process is inherently lossy, since there is no coordination between cancelling and the sending of
 /// messages. A termination signal from either end of the wrapped <see cref="Flow"/> will cause the other end to be terminated,
 /// and any in transit messages will be lost. During backoff, this <see cref="Flow"/> will backpressure.
 /// </para>
 /// <para>This uses the same exponential backoff algorithm as <see cref="BackoffOptions"/>.</para>
 /// </summary>
 /// <param name="flowFactory">A factory for producing the <see cref="Flow"/>] to wrap.</param>
 /// <param name="settings"><see cref="RestartSettings" /> defining restart configuration</param>
 public static Flow <TIn, TOut, NotUsed> WithBackoff <TIn, TOut, TMat>(Func <Flow <TIn, TOut, TMat> > flowFactory, RestartSettings settings)
 => Flow.FromGraph(new RestartWithBackoffFlow <TIn, TOut, TMat>(flowFactory, settings, onlyOnFailures: false));
Пример #14
0
 private Flow <T, T, NotUsed> DelayCancellation <T>(TimeSpan duration) => Flow.FromGraph(new DelayCancellationStage <T>(duration, null));