Commit | Line | Data |
4536f655 |
1 | |
2 | Stem Cell Design Notes |
3 | |
4 | Stem Cells are the fundamental working unit in a Stem application. |
5 | Cells are Perl objects that have 3 primary characteristics: First, they |
6 | must be registered with a Stem address. Second, they must have public |
7 | methods that can take an incoming message as an argument. And third, a |
8 | cell must be able to generate messages. There are three major types of |
9 | Stem Cells: class, object and cloned Cells. These are described in |
10 | further detail below. |
11 | |
12 | Class Cells are created by a Stem class which registers itself (using |
13 | the Stem::Route::register_class routine at module load time) and are |
14 | always registered using its class name. Class Cells are typically |
15 | created by modules which manage some global resource and don't need to |
16 | have multiple object instances created. A common reason for this is a |
17 | module which has a 'status_cmd' (or similar) method that is used to |
18 | get the status of the whole module. The Class Cell registration makes |
19 | those methods accessible via messages. Some Stem classes such as |
20 | Stem::Conf, Stem::Portal, Stem::Msg are Class Cells. Some modules can be |
21 | a Class Cell and also create Object Cells. Class Cells can optionally |
22 | be registered with aliases. The aliases make it easier to send a command |
23 | message from the terminal (using Stem::TtyMsg) to a class Cell |
24 | (Stem::Route is aliased to 'reg', Stem::Cron is aliased to 'cron'). |
25 | |
26 | Object Cells are objects that are created by a class's constructor and |
27 | are then registered with the Stem::Route::register_cell routine. The |
28 | registration takes the object and a required name (unique to this Hub). |
29 | Most often an Object Cell is created by a configuration but any module |
30 | can construct an object and register it. Since configurations can be |
31 | loaded from files and executed anywhere, Stem Cells can be configured at |
32 | any time during the existance of the current Stem system. |
33 | |
34 | Cloned Cells are only created by existing parent Object Cells. (Parent |
35 | Cells are Object Cells set up to create Cloned Cells). When the parent |
36 | Cell gets some form of trigger (typically a socket connection or a |
37 | special command message), it makes a clone of itself and does whatever |
38 | special work the cloned object needs. The parent Cell owns a Stem::Id |
39 | object which it calls to generate a unique (within this Cell) Target |
40 | name which it uses to register the cloned Cell. So the new Cell has a |
41 | unique Cell/Target name pair which can be used in messages directed at |
42 | it. In a typical case, the new Cloned Cell will send a message elsewhere |
43 | informing some other object about its existance; e.g., The Stem::SockMsg |
44 | class can be configured to clone itself when a socket connection is made and |
45 | then it will send a 'pipe_start' command message out. In an Inetd |
46 | configuration that message would be directed to a parent Stem::Proc |
47 | Object Cell which will clone itself and fork a process. This clone will |
48 | respond to the SockMsg message with its new target address, thereby |
49 | setting up a Stem pipe between the socket and process. When either the |
50 | process exits or the socket is closed, the cloned Cells are notified and |
51 | they clean up and unregister themselves. |
52 | |
53 | You can always find the current set of Cells in a Hub by sending a |
54 | 'status' command message to the Class Cell Stem::Route. This is also |
55 | registered with the alias of 'reg'. So from the terminal (if your Hub |
56 | has configured in Stem::TtyMsg) you can type: |
57 | |
58 | reg status |
59 | |
60 | to get the registered Cells in this Hub or |
61 | |
62 | :hubname:reg status |
63 | |
64 | to get the Cells in a remote Hub. |
65 | |
66 | |
67 | When a Stem message is delivered in a Hub, its 'to' address is looked up |
68 | in the Hub's registry and the message is delivered to the destination |
69 | Cell via a method. A Cell must have some well known methods that handle |
70 | incoming messages. These method names have well defined formats and |
71 | uses. In general there are three groups of incoming message methods. All |
72 | of these delivery methods get passed the message itself as their sole |
73 | argument. |
74 | |
75 | The first group of delivery methods are those that handle command |
76 | messages. These are named for the command (the 'cmd' field of a command |
77 | message) with '_cmd' appended. So a foo command message will be |
78 | delivered to the foo_cmd method if it exists in the destination Cell. If |
79 | a command message method returns a value, it is automatically sent back |
80 | to the originating Cell in a response message. |
81 | |
82 | The second group handles all other message types. They are named for the |
83 | message type with a suffix of '_in'. So a 'foo' type message would be |
84 | delivered to the 'foo_in' method if it exists in the destination Cell. A |
85 | very common message type is 'data' and it gets delivered to the |
86 | 'data_in' method. |
87 | |
88 | The final group has the single method 'msg_in' which is used if no other |
89 | method can handle the message. This is the default message delivery |
90 | method. You can have a Cell with just this method and it should be |
91 | designed to handle all expected message types. |
92 | |
93 | The use of specific delivery methods is not critical but it encourages |
94 | cleaner Cell design by having methods focus on doing work and not on |
95 | deciding how to handle different message types. This is in keeping with |
96 | the Stem design philosophy of doing as much common work as possible |
97 | behind the scenes, while leaving only the problem specific work to the |
98 | Cell. |
99 | |
100 | There are no design considerations for sending messages from a Cell. It |
101 | just creates a message object with the class call Stem::Msg->new and |
102 | then dispatches it. If the message doesn't have the 'from' address set, |
103 | it will default to the address of the current Cell (if it is known). If |
104 | the code that generates a new message is not a registered Cell, then you |
105 | must specify the 'from' address as one can't be deduced. |
106 | |
107 | For more on Cell addresses see registry_notes and message_notes. |