Пример #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));
        }
Пример #2
0
        public Unit DeregisterByName(ProcessName name)
        {
            Cluster.Match(
                Some: c =>
            {
                RemoveLocalRegisteredByName(name);
                var regpath = (ProcessId.Top["__registered"][name]).Path;

                // TODO - Make this transactional
                // {
                var pids = c.GetSet <string>(regpath);
                pids.Iter(pid =>
                {
                    c.SetRemove(pid + "-registered", name.Value);
                });
                c.Delete(regpath);
                // }
            },
                None: () =>
            {
                RemoveLocalRegisteredByName(name);
            }
                );
            return(unit);
        }
Пример #3
0
        /// <summary>
        /// Spawns a new process with that routes each message to the Workers
        /// in a round robin fashion.
        /// </summary>
        /// <typeparam name="S">State type</typeparam>
        /// <typeparam name="T">Message type</typeparam>
        /// <param name="Name">Delegator process name</param>
        /// <param name="Flags">Process flags</param>
        /// <returns>Process ID of the delegator process</returns>
        public static ProcessId broadcast <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 = toSet(Workers);

            if (workers.Count < 1)
            {
                throw new ArgumentException($"{nameof(Workers)} should have a length of at least 1");
            }

            var router = spawn <T>(
                Name,
                msg => workers.Iter(pid => fwd(pid)),
                Flags,
                DefaultStrategy,
                MaxMailboxSize,
                Terminated: pid => workers = workers.Remove(pid)
                );

            return(WatchWorkers(router, workers, Options));
        }
Пример #4
0
        internal Actor(
            Option <ICluster> cluster,
            ActorItem parent,
            ProcessName name,
            Func <S, T, S> actor,
            Func <IActor, S> setup,
            Func <S, ProcessId, S> term,
            State <StrategyContext, Unit> strategy,
            ProcessFlags flags,
            ProcessSystemConfig settings,
            IActorSystem sys
            )
        {
            setupFn = setup ?? throw new ArgumentNullException(nameof(setup));
            actorFn = actor ?? throw new ArgumentNullException(nameof(actor));

            this.sys     = sys;
            Id           = parent.Actor.Id[name];
            this.cluster = cluster;
            this.flags   = flags == ProcessFlags.Default
                ? settings.GetProcessFlags(Id)
                : flags;

            termFn = term;

            Parent   = parent;
            Name     = name;
            Strategy = strategy;
            SetupRemoteSubscriptions(cluster, flags);
        }
Пример #5
0
        /// <summary>
        /// Spawns a new process with that routes each message to the Workers
        /// in a round robin fashion.
        /// </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 roundRobin <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 <int, T>(
                Name,
                () => 0,
                (index, msg) =>
            {
                index = index % workers.Length;
                fwd(workers[index]);
                return(index + 1);
            },
                Flags,
                DefaultStrategy,
                MaxMailboxSize,
                Terminated: (index, pid) => { workers = workers.Where(x => x != pid).ToArray(); return(index); }
                );

            return(WatchWorkers(router, workers, Options));
        }
Пример #6
0
        public ActorSystemBootstrap(IActorSystem system, Option <ICluster> cluster, ProcessId rootId, IActor rootProcess, IActorInbox rootInbox, ProcessName rootProcessName, ActorSystemConfig config, ProcessSystemConfig settings, SessionSync sync)
        {
            System = system;
            Sync   = sync;

            var parent = new ActorItem(new NullProcess(system.Name), new NullInbox(), ProcessFlags.Default);

            rootProcess = new Actor <ActorSystemBootstrap, Unit>(
                cluster,
                parent,
                rootProcessName,
                SystemInbox,
                _ => this,
                null,
                Process.DefaultStrategy,
                ProcessFlags.Default,
                settings,
                system
                );

            root            = new ActorItem(rootProcess, rootInbox, rootProcess.Flags);
            Config          = config;
            Settings        = settings;
            Cluster         = cluster;
            RootProcess     = rootProcess;
            RootInbox       = rootInbox;
            RootProcessName = rootProcessName;
        }
Пример #7
0
        /// <summary>
        /// Initialise without a config file or text
        /// </summary>
        /// <param name="systemName">Name of the system - this is most useful</param>
        /// <param name="roleName"></param>
        /// <param name="nodeName"></param>
        /// <param name="providerName"></param>
        /// <param name="connectionString"></param>
        /// <param name="catalogueName"></param>
        /// <returns></returns>
        public static Unit initialise(
            SystemName systemName,
            ProcessName roleName,
            ProcessName nodeName,
            string connectionString,
            string catalogueName,
            string providerName = "redis"
            )
        {
            lock (sync)
            {
                var types = new Types();

                StartFromConfig(new ProcessSystemConfig(
                                    systemName,
                                    nodeName.Value,
                                    HashMap <string, ValueToken>(),
                                    HashMap <ProcessId, ProcessToken>(),
                                    HashMap <string, State <StrategyContext, Unit> >(),
                                    new ClusterToken(
                                        None,
                                        List(
                                            new NamedValueToken("node-name", new ValueToken(types.String, nodeName.Value), None),
                                            new NamedValueToken("role", new ValueToken(types.String, roleName.Value), None),
                                            new NamedValueToken("env", new ValueToken(types.String, systemName.Value), None),
                                            new NamedValueToken("connection", new ValueToken(types.String, connectionString), None),
                                            new NamedValueToken("database", new ValueToken(types.String, catalogueName), None),
                                            new NamedValueToken("provider", new ValueToken(types.String, providerName), None))),
                                    types
                                    ));
            }
            return(unit);
        }
Пример #8
0
        /// <summary>
        /// Create a new process by name.
        /// If this is called from within a process' message loop
        /// then the new process will be a child of the current process.  If it is called from
        /// outside of a process, then it will be made a child of the root 'user' process.
        /// </summary>
        /// <typeparam name="T">Type of messages that the child-process can accept</typeparam>
        /// <param name="Name">Name of the child-process</param>
        /// <param name="Setup">Startup and restart function</param>
        /// <param name="Inbox">Function that is the process</param>
        /// <param name="Flags">Process flags</param>
        /// <param name="Strategy">Failure supervision strategy</param>
        /// <param name="Terminated">Message function to call when a Process [that this Process
        /// watches] terminates</param>
        /// <param name="Lazy">If set to true actor will not start automatically, you need to
        /// startup(processId) manually</param>
        /// <returns>A ProcessId that identifies the child</returns>
        public static ProcessId spawn <S, T>(
            ProcessName Name,
            Func <S> Setup,
            Func <S, T, S> Inbox,
            ProcessFlags Flags = ProcessFlags.Default,
            State <StrategyContext, Unit> Strategy = null,
            int MaxMailboxSize = ProcessSetting.DefaultMailboxSize,
            Func <S, ProcessId, S> Terminated = null,
            Func <S, Unit> Shutdown           = null,
            SystemName System = default(SystemName),
            bool Lazy         = false
            )
        {
            if (System.IsValid && ActorContext.Request != null)
            {
                throw new ProcessException("When spawning you can only specify a System from outside of a Process", ActorContext.Self[Name].Path, "");
            }

            var sys = System.IsValid
                ? ActorContext.System(System)
                : ActorContext.DefaultSystem;

            var parent = System.IsValid
                ? sys.UserContext.Self
                : ActorContext.SelfProcess;

            return(sys.ActorCreate(parent, Name, Inbox, Setup, Shutdown, Terminated, Strategy, Flags, MaxMailboxSize, Lazy));
        }
Пример #9
0
        /// <summary>
        /// Spawns a new process with that routes each message by calling GetHashCode on the
        /// message and modding by the number of workers and using that as the worker index
        /// to route to.
        /// </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 hash <T>(
            ProcessName Name,
            IEnumerable <ProcessId> Workers,
            Func <int, T, int> HashFunc = null,
            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");
            }
            HashFunc = HashFunc ?? DefaultHashFunction <T>();
            var router = spawn <T>(
                Name,
                msg =>
            {
                fwd(workers[HashFunc(Children.Count, msg)]);
            },
                Flags,
                DefaultStrategy,
                MaxMailboxSize,
                Terminated: pid => { workers = workers.Where(x => x != pid).ToArray(); }
                );

            return(WatchWorkers(router, workers, Options));
        }
Пример #10
0
        public ProcessId Register(ProcessName name, ProcessId pid)
        {
            if (!pid.IsValid)
            {
                throw new InvalidProcessIdException();
            }

            Cluster.Match(
                Some: c =>
            {
                if (IsLocal(pid) && GetDispatcher(pid).IsLocal)
                {
                    AddLocalRegistered(name, pid.SetSystem(SystemName));
                }
                else
                {
                    // TODO - Make this transactional
                    // {
                    c.SetAddOrUpdate(ProcessId.Top["__registered"][name].Path, pid.Path);
                    c.SetAddOrUpdate(pid.Path + "-registered", name.Value);
                    // }
                }
            },
                None: () => AddLocalRegistered(name, pid)
                );
            return(Disp["reg"][name]);
        }
Пример #11
0
 /// <summary>
 /// Registers a dispatcher for a role
 /// Dispatchers take in a 'leaf' ProcessId (i.e. /user/my-process) and return an enumerable
 /// of real ProcessIds that the Process system will use to deliver all of the standard functions
 /// like tell, ask, subscribe, etc.
 /// </summary>
 /// <param name="name">Name of the dispatcher</param>
 /// <param name="selector">Function that will be invoked every time a dispatcher based ProcessId
 /// is used.</param>
 /// <returns>A root dispatcher ProcessId.  Use this to create new ProcessIds that will
 /// be passed to the selector function whenever the dispatcher based ProcessId is used</returns>
 public static ProcessId register(ProcessName name, Func <ProcessId, IEnumerable <ProcessId> > selector)
 {
     lock (sync)
     {
         dispatchers = dispatchers.AddOrUpdate(name, selector);
     }
     return(ProcessId.Top["disp"][name]);
 }
Пример #12
0
 public ProcessIdInternal(ProcessName[] parts, ProcessName name, SystemName system, string path)
 {
     Parts  = parts ?? throw new ArgumentNullException(nameof(parts));
     Name   = name;
     System = system;
     Path   = path ?? throw new ArgumentNullException(nameof(path));
     IsDisp = path.StartsWith(Disp);
 }
Пример #13
0
 /// <summary>
 /// Removes the dispatcher registration for the named dispatcher
 /// </summary>
 /// <param name="name">Name of the dispatcher to remove</param>
 public static Unit deregister(ProcessName name)
 {
     lock (sync)
     {
         dispatchers = dispatchers.Remove(name);
     }
     return(unit);
 }
Пример #14
0
        /// <summary>
        /// Spawns a new process with Count worker processes, each message is mapped
        /// and sent to the least busy worker
        /// </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 leastBusyMap <S, T, U>(
            ProcessName Name,
            int Count,
            Func <S> Setup,
            Func <S, U, S> Inbox,
            Func <T, U> Map,
            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 (Setup == null)
            {
                throw new ArgumentNullException(nameof(Setup));
            }
            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 umsg = Map(msg);

                var disps = (from child in Children.Map(c => Tuple(c, ActorContext.System(c).GetDispatcher(c))).Values
                             let count = child.Item2.GetInboxCount()
                                         where count >= 0
                                         orderby count
                                         select child)
                            .ToList();

                if (disps.Count == 0)
                {
                    throw new NoRouterWorkersException();
                }
                else
                {
                    fwd(disps.First().Item1, umsg);
                }
                return unit;
            },
                       Flags,
                       Strategy,
                       MaxMailboxSize
                       ));
        }
Пример #15
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
                       ));
        }
Пример #16
0
 /// <summary>
 /// Create a new process by name (accepts Unit as a return value instead of void).
 /// If this is called from within a process' message loop
 /// then the new process will be a child of the current process.  If it is called from
 /// outside of a process, then it will be made a child of the root 'user' process.
 /// </summary>
 /// <typeparam name="T">Type of messages that the child-process can accept</typeparam>
 /// <param name="Name">Name of the child-process</param>
 /// <param name="Inbox">Function that is the process</param>
 /// <param name="Flags">Process flags</param>
 /// <param name="Strategy">Failure supervision strategy</param>
 /// <param name="Terminated">Message function to call when a Process [that this Process
 /// watches] terminates</param>
 /// <returns>A ProcessId that identifies the child</returns>
 public static ProcessId spawnUnit <T>(
     ProcessName Name,
     Func <T, Unit> Inbox,
     ProcessFlags Flags = ProcessFlags.Default,
     State <StrategyContext, Unit> Strategy = null,
     int MaxMailboxSize = ProcessSetting.DefaultMailboxSize,
     Func <ProcessId, Unit> Terminated = null
     ) =>
 spawn <Unit, T>(Name, () => unit, (state, msg) => { Inbox(msg); return(state); }, Flags, Strategy, MaxMailboxSize, (state, pid) => { Terminated(pid); return(state); });
Пример #17
0
 public static ProcessId spawnRoundRobin <T>(
     ProcessName Name,
     int Count,
     Action <T> Inbox,
     ProcessFlags Flags = ProcessFlags.Default,
     State <StrategyContext, Unit> Strategy = null,
     int MaxMailboxSize = ProcessSetting.DefaultMailboxSize
     ) =>
 Router.roundRobin(Name, Count, Inbox, Flags, Strategy, MaxMailboxSize);
Пример #18
0
 /// <summary>
 /// Create N child processes.
 /// The name provided will be used as a basis to generate the child names.  Each child will
 /// be named "name-index" where index starts at zero.
 /// If this is called from within a process' message loop
 /// then the new processes will be a children of the current process.  If it is called from
 /// outside of a process, then they will be made a child of the root 'user' process.
 /// </summary>
 /// <typeparam name="T">Type of messages that the child-process can accept</typeparam>
 /// <param name="Count">Number of processes to spawn</param>
 /// <param name="Name">Name of the child-process</param>
 /// <param name="Inbox">Function that is the process</param>
 /// <param name="Flags">Process flags</param>
 /// <param name="Strategy">Failure supervision strategy</param>
 /// <param name="MaxMailboxSize">Maximum inbox size</param>
 /// <param name="Terminated">Message function to call when a Process [that this Process
 /// watches] terminates</param>
 /// <returns>ProcessId IEnumerable</returns>
 public static IEnumerable <ProcessId> spawnMany <T>(
     int Count,
     ProcessName Name,
     Action <T> Inbox,
     ProcessFlags Flags = ProcessFlags.Default,
     State <StrategyContext, Unit> Strategy = null,
     int MaxMailboxSize            = ProcessSetting.DefaultMailboxSize,
     Action <ProcessId> Terminated = null
     ) =>
 Range(0, Count).Map(n => spawn($"{Name}-{n}", Inbox, Flags, Strategy, MaxMailboxSize, Terminated)).ToList();
Пример #19
0
 /// <summary>
 /// Spawns a new process with Count worker processes, each message is sent to one worker
 /// process in a round robin fashion.
 /// </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 broadcast <T>(
     ProcessName Name,
     int Count,
     Action <T> Inbox,
     ProcessFlags Flags = ProcessFlags.Default,
     State <StrategyContext, Unit> Strategy = null,
     int MaxMailboxSize = ProcessSetting.DefaultMailboxSize,
     string WorkerName  = "worker"
     ) =>
 broadcast <Unit, T>(Name, Count, () => unit, (_, msg) => { Inbox(msg); return(unit); }, Flags, Strategy, MaxMailboxSize, WorkerName);
Пример #20
0
 /// <summary>
 /// Create N child processes.
 /// The name provided will be used as a basis to generate the child names.  Each child will
 /// be named "name-index" where index starts at zero.
 /// If this is called from within a process' message loop
 /// then the new processes will be a children of the current process.  If it is called from
 /// outside of a process, then they will be made a child of the root 'user' process.
 /// </summary>
 /// <typeparam name="S">State type</typeparam>
 /// <typeparam name="T">Type of messages that the child-process can accept</typeparam>
 /// <param name="Spec">Map of IDs and State for generating child workers</param>
 /// <param name="Name">Name of the child-process</param>
 /// <param name="Inbox">Function that is the process</param>
 /// <param name="Flags">Process flags</param>
 /// <param name="Strategy">Failure supervision strategy</param>
 /// <param name="Terminated">Message function to call when a Process [that this Process
 /// watches] terminates</param>
 /// <returns>ProcessId IEnumerable</returns>
 public static IEnumerable <ProcessId> spawnMany <S, T>(
     ProcessName Name,
     Map <int, Func <S> > Spec,
     Func <S, T, S> Inbox,
     ProcessFlags Flags = ProcessFlags.Default,
     State <StrategyContext, Unit> Strategy = null,
     int MaxMailboxSize = ProcessSetting.DefaultMailboxSize,
     Func <S, ProcessId, S> Terminated = null
     ) =>
 Spec.Map((id, state) => ActorContext.System(default(SystemName)).ActorCreate(ActorContext.SelfProcess, $"{Name}-{id}", Inbox, state, Terminated, Strategy, Flags, MaxMailboxSize, false)).Values.ToList();
Пример #21
0
 public ProcessId ActorCreate <S, T>(
     ActorItem parent,
     ProcessName name,
     Func <T, Unit> actorFn,
     Func <S, ProcessId, S> termFn,
     State <StrategyContext, Unit> strategy,
     ProcessFlags flags,
     int maxMailboxSize,
     bool lazy) =>
 ActorCreate <S, T>(parent, name, (s, t) => { actorFn(t); return(default(S)); }, () => default(S), termFn, strategy, flags, maxMailboxSize, lazy);
Пример #22
0
 /// <summary>
 /// Create N child processes.
 /// The name provided will be used as a basis to generate the child names.  Each child will
 /// be named "name-index" where index starts at zero.
 /// If this is called from within a process' message loop
 /// then the new processes will be a children of the current process.  If it is called from
 /// outside of a process, then they will be made a child of the root 'user' process.
 /// </summary>
 /// <typeparam name="T">Type of messages that the child-process can accept</typeparam>
 /// <param name="Count">Number of processes to spawn</param>
 /// <param name="Setup">Startup and restart function</param>
 /// <param name="Name">Name of the child-process</param>
 /// <param name="Inbox">Function that is the process</param>
 /// <param name="Flags">Process flags</param>
 /// <param name="Strategy">Failure supervision strategy</param>
 /// <param name="Terminated">Message function to call when a Process [that this Process
 /// watches] terminates</param>
 /// <returns>ProcessId IEnumerable</returns>
 public static IEnumerable <ProcessId> spawnMany <S, T>(
     int Count,
     ProcessName Name,
     Func <S> Setup,
     Func <S, T, S> Inbox,
     ProcessFlags Flags = ProcessFlags.Default,
     State <StrategyContext, Unit> Strategy = null,
     int MaxMailboxSize = ProcessSetting.DefaultMailboxSize,
     Func <S, ProcessId, S> Terminated = null
     ) =>
 Range(0, Count).Map(n => ActorContext.System(default(SystemName)).ActorCreate(ActorContext.SelfProcess, $"{Name}-{n}", Inbox, Setup, Terminated, Strategy, Flags, MaxMailboxSize, false)).ToList();
Пример #23
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 in a round robin fashion.
 /// </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 broadcastMapMany <T, U>(
     ProcessName Name,
     int Count,
     Action <U> Inbox,
     Func <T, IEnumerable <U> > MapMany,
     ProcessFlags Flags = ProcessFlags.Default,
     State <StrategyContext, Unit> Strategy = null,
     int MaxMailboxSize = ProcessSetting.DefaultMailboxSize,
     string WorkerName  = "worker"
     ) =>
 broadcastMapMany(Name, Count, () => unit, (_, umsg) => { Inbox(umsg); return(unit); }, MapMany, Flags, Strategy, MaxMailboxSize, WorkerName);
Пример #24
0
 /// <summary>
 /// Spawns a new process with Count worker processes, each message is mapped
 /// and sent to the least busy worker.
 /// </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 leastBusyMap <T, U>(
     ProcessName Name,
     int Count,
     Action <U> Inbox,
     Func <T, U> Map,
     ProcessFlags Flags = ProcessFlags.Default,
     State <StrategyContext, Unit> Strategy = null,
     int MaxMailboxSize = ProcessSetting.DefaultMailboxSize,
     string WorkerName  = "worker"
     ) =>
 leastBusyMap(Name, Count, () => unit, (_, umsg) => { Inbox(umsg); return(unit); }, Map, Flags, Strategy, MaxMailboxSize, WorkerName);
Пример #25
0
        /// <summary>
        /// Spawns a new process with Count worker processes, each message is sent to a worker
        /// process by calling GetHashCode on the message and modding by the number of workers
        /// and using that to find the worker index to route to.
        /// </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 hashMap <S, T, U>(
            ProcessName Name,
            int Count,
            Func <S> Setup,
            Func <S, U, S> Inbox,
            Func <T, U> Map,
            Func <int, T, int> HashFunc            = null,
            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 (Setup == null)
            {
                throw new ArgumentNullException(nameof(Setup));
            }
            if (Count < 1)
            {
                throw new ArgumentException($"{nameof(Count)} should be greater than 0");
            }
            HashFunc = HashFunc ?? DefaultHashFunction <T>();

            return(spawn <Unit, T>(
                       Name,
                       () =>
            {
                spawnMany(Count, WorkerName, Setup, Inbox, Flags);
                return unit;
            },
                       (_, msg) =>
            {
                var umsg = Map(msg);
                var child = Children.Skip(HashFunc(Children.Count, msg)).Take(1).ToArray();
                if (child.Length == 0)
                {
                    throw new NoRouterWorkersException();
                }
                else
                {
                    fwd(child[0].Value, umsg);
                }
                return unit;
            },
                       Flags,
                       Strategy,
                       MaxMailboxSize
                       ));
        }
Пример #26
0
 public ClusterConfig(
     ProcessName nodeName,
     string connectionString,
     string catalogueName,
     ProcessName role
     )
 {
     NodeName         = nodeName;
     ConnectionString = connectionString;
     CatalogueName    = catalogueName;
     Role             = role;
 }
Пример #27
0
 /// <param name="nodeName">Unique name for this process.  It becomes the name of the root
 /// node and allows other services on the cluster to discover you and communicate with you.
 /// </param>
 /// <param name="connectionString">Provider defined connection string</param>
 /// <param name="catalogueName">>Provider defined catalogue name</param>
 public static ClusterConfig config(
     ProcessName nodeName,
     string connectionString,
     string catalogueName,
     ProcessName role
     ) =>
 new ClusterConfig(
     nodeName,
     connectionString,
     catalogueName,
     role
     );
Пример #28
0
        void RemoveLocalRegisteredByName(ProcessName name)
        {
            lock (regsync)
            {
                var pids = registeredProcessNames.Find(name).IfNone(Set <ProcessId>());

                pids.Iter(pid =>
                          registeredProcessIds = registeredProcessIds.SetItem(pid, registeredProcessIds[pid].Remove(name))
                          );
                registeredProcessNames = registeredProcessNames.Remove(name);
            }
        }
Пример #29
0
 public ProcessId ActorCreate <S, T>(
     ActorItem parent,
     ProcessName name,
     Func <S, T, S> actorFn,
     Func <S> setupFn,
     Func <S, ProcessId, S> termFn,
     State <StrategyContext, Unit> strategy,
     ProcessFlags flags,
     int maxMailboxSize,
     bool lazy
     ) =>
 ActorCreate(parent, name, actorFn, _ => setupFn(), termFn, strategy, flags, maxMailboxSize, lazy);
Пример #30
0
        private Unit RemoveWatchingOfRemote(ProcessName node)
        {
            var root = ProcessId.Top[node];

            foreach (var watching in watchings)
            {
                if (watching.Key.Take(1) == root)
                {
                    RemoteDispatchTerminate(watching.Key);
                }
            }
            return(unit);
        }