/// <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))); }
/// <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))); }
/// <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); }))); }
/// <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));
/// <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));
/// <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));
private Flow <T, T, NotUsed> DelayCancellation <T>(TimeSpan duration) => Flow.FromGraph(new DelayCancellationStage <T>(duration, null));