Exemplo n.º 1
0
        /// <summary>
        /// Spawns a new process with that routes each message to the Workers
        /// randomly.
        /// </summary>
        /// <typeparam name="S">State type</typeparam>
        /// <typeparam name="T">Message type</typeparam>
        /// <param name="Name">Delegator process name</param>
        /// <param name="Count">Number of worker processes</param>
        /// <param name="Inbox">Worker message handler</param>
        /// <param name="Flags">Process flags</param>
        /// <param name="Strategy">Failure supervision strategy</param>
        /// <returns>Process ID of the delegator process</returns>
        public static ProcessId random <T>(
            ProcessName Name,
            IEnumerable <ProcessId> Workers,
            RouterOption Options = RouterOption.Default,
            ProcessFlags Flags   = ProcessFlags.Default,
            int MaxMailboxSize   = ProcessSetting.DefaultMailboxSize
            )
        {
            if (Workers == null)
            {
                throw new ArgumentNullException(nameof(Workers));
            }
            var workers = Workers.ToArray();

            if (workers.Length < 1)
            {
                throw new ArgumentException($"{nameof(Workers)} should have a length of at least 1");
            }
            var router = spawn <T>(
                Name,
                msg => fwd(workers[Prelude.random(workers.Length)]),
                Flags,
                DefaultStrategy,
                MaxMailboxSize,
                Terminated: pid => workers = workers.Where(x => x != pid).ToArray()
                );

            return(WatchWorkers(router, workers, Options));
        }
Exemplo n.º 2
0
        /// <summary>
        /// Spawns a new process with N worker processes, each message is mapped
        /// from T to IEnumerable U before each resulting U is passed to the worker
        /// processes randomly.
        /// </summary>
        /// <typeparam name="T">Message type</typeparam>
        /// <typeparam name="U">Mapped message type</typeparam>
        /// <param name="Name">Delegator process name</param>
        /// <param name="Count">Number of worker processes</param>
        /// <param name="map">Maps the message from T to IEnumerable U before each one is passed to the workers</param>
        /// <param name="Inbox">Worker message handler</param>
        /// <param name="Flags">Process flags</param>
        /// <param name="Strategy">Failure supervision strategy</param>
        /// <returns>Process ID of the delegator process</returns>
        public static ProcessId randomMapMany <S, T, U>(
            ProcessName Name,
            int Count,
            Func <S> Setup,
            Func <S, U, S> Inbox,
            Func <T, IEnumerable <U> > MapMany,
            ProcessFlags Flags = ProcessFlags.Default,
            State <StrategyContext, Unit> Strategy = null,
            int MaxMailboxSize = ProcessSetting.DefaultMailboxSize,
            string WorkerName  = "worker"
            )
        {
            if (Inbox == null)
            {
                throw new ArgumentNullException(nameof(Inbox));
            }
            if (WorkerName == null)
            {
                throw new ArgumentNullException(nameof(WorkerName));
            }
            if (Count < 1)
            {
                throw new ArgumentException($"{nameof(Count)} should be greater than 0");
            }

            return(spawn <Unit, T>(
                       Name,
                       () =>
            {
                spawnMany(Count, WorkerName, Setup, Inbox, Flags);
                return unit;
            },
                       (_, msg) =>
            {
                var us = MapMany(msg);

                foreach (var u in us)
                {
                    var index = Prelude.random(Children.Count);
                    var child = Children.Skip(index).Take(1).ToArray();

                    if (child.Length == 0)
                    {
                        throw new NoRouterWorkersException();
                    }
                    else
                    {
                        fwd(child[0].Value, u);
                    }
                }
                return unit;
            },
                       Flags,
                       Strategy,
                       MaxMailboxSize
                       ));
        }
Exemplo n.º 3
0
        /// <summary>
        /// Static ctor
        /// Sets up the default roles
        /// </summary>
        static Role()
        {
            ProcessName first      = "role-first";
            ProcessName second     = "role-second";
            ProcessName third      = "role-third";
            ProcessName last       = "role-last";
            ProcessName next       = "role-next";
            ProcessName prev       = "role-prev";
            ProcessName broadcast  = "role-broadcast";
            ProcessName leastBusy  = "role-least-busy";
            ProcessName random     = "role-random";
            ProcessName roundRobin = "role-round-robin";

            var nextNode = fun((bool fwd) => fun((ProcessId leaf) =>
            {
                var self    = leaf.Take(1).GetName();
                var isNext  = false;
                var nodeMap = Nodes(leaf);

                var nodes = fwd
                    ? nodeMap.Values.Append(nodeMap.Values)
                    : nodeMap.Values.Append(nodeMap.Values).Reverse(); //< TODO: Inefficient

                foreach (var node in nodes)
                {
                    if (isNext)
                    {
                        return(new[] { ProcessId.Top[node.NodeName].Append(leaf.Skip(1)) }.AsEnumerable());
                    }

                    if (node.NodeName == self)
                    {
                        isNext = true;
                    }
                }
                return(new ProcessId[0].AsEnumerable());
            }));

            // Next
            nextRoot = Dispatch.register(next, nextNode(true));

            // Prev
            prevRoot = Dispatch.register(prev, nextNode(false));

            // First
            First = Dispatch.register(first, leaf => NodeIds(leaf).Take(1));

            // Second
            Second = Dispatch.register(second, leaf => NodeIds(leaf).Skip(1).Take(1));

            // Third
            Third = Dispatch.register(third, leaf => NodeIds(leaf).Skip(2).Take(1));

            // Last
            Last = Dispatch.register(last, leaf => NodeIds(leaf).Reverse().Take(1));

            // Broadcast
            Broadcast = Dispatch.register(broadcast, NodeIds);

            // Least busy
            LeastBusy = Dispatch.register(leastBusy, leaf =>
                                          NodeIds(leaf)
                                          .Map(pid => Tuple(inboxCount(pid), pid))
                                          .OrderBy(tup => tup.Item1)
                                          .Map(tup => tup.Item2)
                                          .Take(1));

            // Random
            Random = Dispatch.register(random, leaf => {
                var workers = NodeIds(leaf).ToArray();
                return(new ProcessId[1] {
                    workers[Prelude.random(workers.Length)]
                });
            });

            // Round-robin
            object            sync            = new object();
            Map <string, int> roundRobinState = Map.empty <string, int>();

            RoundRobin = Dispatch.register(roundRobin, leaf => {
                var key     = leaf.ToString();
                var workers = NodeIds(leaf).ToArray();
                int index   = 0;
                lock (sync)
                {
                    roundRobinState = roundRobinState.AddOrUpdate(key, x => { index = x % workers.Length; return(x + 1); }, 0);
                }
                return(new ProcessId[1] {
                    workers[index]
                });
            });
        }
Exemplo n.º 4
0
        static Dispatch()
        {
            ProcessName broadcast  = "broadcast";
            ProcessName leastBusy  = "least-busy";
            ProcessName random     = "random";
            ProcessName roundRobin = "round-robin";

            ProcessName first  = "first";
            ProcessName second = "second";
            ProcessName third  = "third";
            ProcessName last   = "last";

            var processes = fun((ProcessId leaf) =>
            {
                if (!leaf.IsValid)
                {
                    return(new ProcessId[0]);
                }
                if (leaf.IsSelection)
                {
                    return(leaf.GetSelection());
                }
                if (leaf.Head().Name == "disp")
                {
                    leaf = leaf.Skip(1);
                    if (!leaf.IsValid)
                    {
                        return(new ProcessId[0]);
                    }
                    return(getFunc(leaf.Head().Name)(leaf.Skip(1)));
                }
                return(new ProcessId[1] {
                    leaf
                });
            });

            // Broadcast
            Broadcast = register(broadcast, processes);

            // First
            First = register(first, leaf => processes(leaf).Take(1));

            // Second
            Second = register(second, leaf => processes(leaf).Skip(1).Take(1));

            // Third
            Third = register(third, leaf => processes(leaf).Skip(2).Take(1));

            // Last
            Last = register(last, leaf => processes(leaf).Reverse().Take(1));

            // Least busy
            LeastBusy = register(leastBusy, leaf =>
                                 processes(leaf)
                                 .Map(pid => Tuple(inboxCount(pid), pid))
                                 .OrderBy(tup => tup.Item1)
                                 .Map(tup => tup.Item2)
                                 .Take(1));

            // Random
            Random = register(random, leaf => {
                var workers = processes(leaf).ToArray();
                return(new ProcessId[1] {
                    workers[Prelude.random(workers.Length)]
                });
            });

            // Round-robin
            object            sync            = new object();
            Map <string, int> roundRobinState = Map.empty <string, int>();

            RoundRobin = register(roundRobin, leaf => {
                var key     = leaf.ToString();
                var workers = processes(leaf).ToArray();
                int index   = 0;
                lock (sync)
                {
                    roundRobinState = roundRobinState.AddOrUpdate(key, x => { index = x % workers.Length; return(x + 1); }, 0);
                }
                return(new ProcessId[1] {
                    workers[index]
                });
            });
        }