I am trying to make an activity diagram of a user for my system and I am unsure if the flow should come down to a Join Node or Merge Node before the user can log off. Here is the one I have made sa of now. Could anyone explain to me what's the difference?
It must be a join (though I first remembered wrongly and thanks to #AxelScheithauer pointing out my error). P. 401 of UML 2.5
15.5.3.1 Executable Nodes
...
When an ExecutableNode completes an execution, the control token representing that execution is removed from the ExecutableNode and control tokens are offered on all outgoing ControlFlows of the ExecutableNode. That is, there is an implicit fork of the flow of control from the ExecutableNode to its outgoing ControlFlows.
That means that all 6 actions below will start in parallel which does not mean they must run concurrently. But all of them need completion in order to continue after the join below. (I doubt that this is desired.)
There's a (double) 2nd flaw in the top decision back-flows. They need to go back to the top merge. Otherwise neither Login nor Register would start since they expect 3 or 2 tokens where only one would arrive.
Related
Consider the simplest ExpansionRegion of mode stream. According to UML Documentation (16.12 Expansion Regions)
If the value [of mode] is stream, there is exactly one expansion execution, and element values are offered to this execution in a stream from each collection. That is, each element of a collection on an input ElementNode is offered separately as a token, one by one, on all outgoing ActivityEdges from the ExpansionNode
But this ExpansionRegion will never end! As soon as all tokens from input ExpansionNode are processed, Do something will be waiting indefinitely for a token from input, which will never come! How do I terminate this ExpansionRegion?
Update: it seems the only solution I could find is the following (but I'm not sure, see below) :
When there are no more tokens available from input then the control token from Do something is not accepted by Do something through C.3-C.4-C.2 path since according to 16.2.3.4 Actions and Pins in Activities
Executing an Action in an Activity requires all of its InputPins to be offered all necessary tokens, as specified by their
minimum multiplicity
and according to 15.2.3.2 Activity Nodes
When an ActivityNode begins execution, tokens are
accepted from some or all of its incoming ActivityEdges and a token is placed on the node.
so it seems reasonable to conclude from the above that Action (i.e. Do something) will not accept a control token if it is not able to execute so Decision node will pass the token to control flow C.5 since it has "else" guard and according to 15.3.3.6 Decision Nodes:
For use only with DecisionNodes, a predefined guard “else” represented as an Expression with “else” as its operator and no operands) may be used for at most one outgoing edge. This guard evaluates to true only if the token is not accepted by any other outgoing edge from the DecisionNode.
Update 2: Is the loop (C.1-C.2-C.3) required? It seems to me the answer is "yes" because without it Do something would process just one object token! I.e. Do something would receive a single control token at the ExpansionRegion's invocation according to 15.2.3.6 Activity Execution
When an Activity is first invoked, none of its nodes other than input ActivityParameterNodes will initially hold any tokens. However, nodes that do not have incoming edges and require no input data to execute are immediately enabled. A single control token is placed on each enabled node and they begin executing concurrently. Such nodes include ExecutableNodes (see sub clause 15.5) with no incoming ControlFlows and no mandatory input data and InitialNodes (see sub clause 15.3).
and according to 15.5.3.1 Executable Nodes
When an ExecutableNode completes an execution, the control token representing that execution is removed from the
ExecutableNode and control tokens are offered on all outgoing ControlFlows of the ExecutableNode.
Are there any clarification in UML Documentation saying that control token could "stay" on Do something (without the loop) and re-enable its execution to process next object token?
You seem to think that you modeled a deadlock. Actually, UML Activities cannot have deadlocks by definition. The execution of all action containers (Activitys and StructuredActivityNodes with their subtypes) ends when none of the contained actions is enabled.
StructuredActivityNode: A StructuredActivityNode completes execution according to the same rules as for the completion of the execution of an Activity, including terminating execution due to an ActivityFinalNode.
Activity: The execution of an Activity with no streaming Parameters completes when it has no nodes executing and no nodes
enabled for execution, or when it is explicitly terminated using an ActivityFinalNode.
After processing the last element in the input collection, no action is enabled anymore and therefore, the expansion region ends and offers the output collection to the outgoing object flow. Therefore, the initial node and all the control flows are not needed.
Having said that, it is possible, that you need control flows, because you have additional actions. Let's say you need to initialize the system before the first execution and Do something else after each execution of Do something. Your first example works well for this. Just place initialize on C.1 and Do something else on C.3.
Your second solution could be used, if you have to do some cleanup before leaving the expansion region. Just place it on C.5. I was not aware, that this would work, but after rereading the specification text cited by you, I agree that it is working.
It seems like you missed the point that object tokens are sufficient to trigger an action - without any need for a control token.
UML 2.5 p. 374:
15.2.3.4 Object Flows
Object tokens pass over ObjectFlows, carrying data through an Activity via their values, or carrying no data ( null tokens). A null token can still be passed along an ObjectFlow and used like any other token. For example, an Action can output a null token to explicitly indicate that it did not produce an optional value, and a downstream DecisionNode (see sub clause 15.3) can test for this and branch accordingly.
So once you get rid of the start node and the superfluous control structures you will get the desired behavior: the action starts with receiving an object and ends when emitting the resulting object.
I could not find a full fledged example on the fly, but that picture illustrates it well enough:
Longer explanation
P. 478 of UML 2.5: (please look into the specs for more details)
16.12 Expansion Regions
16.12.1 Summary
An ExpansionRegion is a StructuredActivityNode that executes its contained elements multiple times corresponding to elements of an input collection.
[...]
16.12.3 Semantics
An ExpansionRegion is a StructuredActivityNode that takes as input one or more collections of values and executes its contained ActivityNodes and ActivityEdges on each value in those collections. If the computation produces results, these may be collected into output collections. The number of output collections can differ from the number of input collections.
[...]
16.12.4 Notation
An ExpansionRegion is shown as a dashed rounded box with one of the keywords «parallel», «iterative» or «stream» in the upper left corner (see Figure 16.48). Input and output ExpansionNodes are drawn as small rectangles divided by vertical bars into small compartments.
[...]
As you can see, the expansion region is a "simple" action that takes an object and returns another. As such it's like any simple action with an input pin like shown above in my answer. That means it will start upon receipt of an object and emit an (eventually empty) object when it's done.
I am creating an activity diagram
Admin log in to the web
If validated, it reaches the dashboard
Through dashboard it can manage account, manage product and manages issues
after performing one of above options, it can go back to dashboard or logout from system.
I have used fork/join, is it correct or I should be using decision/merge instead
2ndly, is the procedure of logging out or performing another option available in dashboard correctly defined?
Your activity is having several issues.
First and most severe, it will not do anything because actions (and mostly those - not all model elements in activities) having an "implicit and sematics" for incomming control flows. This means that an action is only executed when an token is offered on ALL incomming control flow actions, otherwise it waits. So as your control flow from validate can not offer an token before Login has been executed and finished, you are having a lock. And nothing is executed. The same applies to Dashboard. To solve this you need to model merge nodes.
The second point is that you only want to execute (according to your description) one of the manage actions. (Btw. names with generic verbs like "manage", "maintain", "do", "perform", etc. are quite bad names for actions, use more specific ones instead). Your model executes, irregardless of the selection in the dashboard action, all manage actions concurrently. Concurrently means in an arbitrary order and does not demand a parallel execution. Thus you should replace the fork with a decision node, where the conditions on the outgoing flows are based on the selection from the dashboard. An decision node can have an arbitrary (but finite) number of outgoing control flows. All the outgoing control flows from the manage actions are merged using a merge node instead of a join node. As the join node would wait for an incommingtoken per incomming control flow.
A minor point, that would be solved when using an UML/SysML tool is that the fork and join nodes are bars and not rectangular frames.
Your AD has 2 flaws. First a fork/join is a solid thick line, but not a hollow rectangle. Second, it's used wrongly. This way you run all Manage actions in parallel and continue when they are all finished. According to your description use a diamond to decide for one of the actions Also use the diamond afterwards to merge the flows and continue to Logout.
I have a function.
Which for example goes like this:
Function start:
...
if statement{
set variable
}
if second if{}
contintue
This code I try to put into a UML, Activity diagram.
I wondered if my forking is done right, or do I need to use a forking symbol. So I have a split where it eventually gets into the if statement ( difference in totals). But after the if (or even if the if is not even executed) the next if statement will be executed (regardless of first if result).
If you want to have conditional paths you need to use decision nodes. Imagine a virtual token to represent the execution flow. When you are at an action that has multiple (unguarded) control flows leaving it, each will take a token (the UML spec calls that implicit fork) an execution will continue in parallel. So either you add guards to each of the outgoing control flows or you use a decision node. Though you should (or better must) use guards here too you have only a single token that will leave the decision node. Without proper guards it will be undecided which of the outgoing flows will take the token.
Implicit fork:
Only one token continues:
One token for sure and eventually a 2nd in parallel:
(I'm not 100% sure if that's really true. It's a notation I'd never use.)
Only one token continues, but not defined which (due to no guards):
I have a web service that use Rebus as Service Bus.
Rebus is configured as explained in this post.
The web service is load balanced with a two servers cluster.
These services are for a production environment and each production machine sends commands to save the produced quantities and/or to update its state.
In the BL I've modelled an Aggregate Root for each machine and it executes the commands emitted by the real machine. To preserve the correct status, the Aggregate needs to receive the commands in the same sequence as they were emitted, and, since there is no concurrency for that machine, that is the same order they are saved on the bus.
E.G.: the machine XX sends a command of 'add new piece done' and then the command 'Set stop for maintenance'. Executing these commands in a sequence you should have Aggregate XX in state 'Stop', but, with multiple server/worker roles, you could have that both commands are executed at the same time on the same version of Aggregate. This means that, depending on who saves the aggregate first, I can have Aggregate XX with state 'Stop' or 'Producing pieces' ... that is not the same thing.
I've introduced a Service Bus to add scale out as the number of machine scales and resilience (if a server fails I have only slowdown in processing commands).
Actually I'm using the name of the aggregate like a "topic" or "destinationAddress" with the IAdvancedApi, so the name of the aggregate is saved into the recipient of the transport. Then I've created a custom Transport class that:
1. does not remove the messages in progress but sets them in state
InProgress.
2. to retrive the messages selects only those that are in a recipient that have no one InProgress.
I'm wandering: is this the best way to guarantee that the bus executes the commands for aggregate in the same sequence as they arrived?
The solution would be have some kind of locking of your aggregate root, which needs to happen at the data store level.
E.g. by using optimistic locking (probably implemented with some kind of revision number or something like that), you would be sure that you would never accidentally overwrite another node's edits.
This would allow for your aggregate to either
a) accept the changes in either order (which is generally preferable – makes your system more tolerant), or
b) reject an invalid change
If the aggregate rejects the change, this could be implemented by throwing an exception. And then, in the Rebus handler that catches this exception, you can e.g. await bus.Defer(TimeSpan.FromSeconds(5), theMessage) which will cause it to be delivered again in five seconds.
You should never rely on message order in a service bus / queuing / messaging environment.
When you do find yourself in this position you may need to re-think your design. Firstly, a service bus is most certainly not an event store and attempting to use it like one is going to lead to pain and suffering :) --- not that you are attempting this but I thought I'd throw it in there.
As for your design, in order to manage this kind of state you may want to look at a process manager. If you are not generating those commands then even this will not help.
However, given your scenario it seems as though the calls are sequential but perhaps it is just your example. In any event, as mookid8000 said, you either want to:
discard invalid changes (with the appropriate feedback),
allow any order of messages as long as they are valid,
ignore out-of-sequence messages till later.
Hope that helps...
"exactly the same sequence as they were saved on the bus"
Just... why?
Would you rely on your HTTP server logs to know which command actually reached an aggregate first? No because it is totally unreliable, just like it is with at-least-one delivery guarantees and it's also irrelevant.
It is your event store and/or normal persistence state that should be the source of truth when it comes to knowing the sequence of events. The order of commands shouldn't really matter.
Assuming optimistic concurrency, if the aggregate is not allowed to transition from A to C then it should guard this invariant and when a TransitionToStateC command will hit it in the A state it will simply get rejected.
If on the other hand, A->C->B transitions are valid and that is the order received by your aggregate well that is what happened from the domain perspective. It really shouldn't matter which command was published first on the bus, just like it doesn't matter which user executed the command first from the UI.
"In my scenario the calls for a specific aggregate are absolutely
sequential and I must guarantee that are executed in the same order"
Why are you executing them asynchronously and potentially concurrently by publishing on a bus then? What you are basically saying is that calls are sequential and cannot be processed concurrently. That means everything should be synchronous because there is no potential benefit from parallelism.
Why:
executeAsync(command1)
executeAsync(command2)
executeAsync(command3)
When you want:
execute(command1)
execute(command2)
execute(command3)
You should have a single command message and the handler of this message executes multiple commands against the aggregate. Then again, in this case I'd just create a single operation on the aggregate that performs all the transitions.
Greetings SO denizens!
I'm trying to architect an overhaul of an existing NodeJS application that has outgrown its original design. The solutions I'm working towards are well beyond my experience.
The system has ~50 unique async tasks defined as various finite state machines which it knows how to perform. Each task has a required set of parameters to begin execution which may be supplied by interactive prompts, a database or from the results of a previously completed async task.
I have a UI where the user may define a directed graph ("the flow"), specifying which tasks they want to run and the order they want to execute them in with additional properties associated with both the vertices and edges such as extra conditionals to evaluate before calling a child task(s). This information is stored in a third normal form PostgreSQL database as a "parent + child + property value" configuration which seems to work fairly well.
Because of the sheer number of permutations, conditionals and absurd number of possible points of failure I'm leaning towards expressing "the flow" as a state machine. I merely have just enough knowledge of graph theory and state machines to implement them but practically zero background.
I think what I'm trying to accomplish is at the flow run time after user input for the root services have been received, is somehow compile the database representation of the graph + properties into a state machine of some variety.
To further complicate the matter in the near future I would like to be able to "pause" a flow, save its state to memory, load it on another worker some time in the future and resume execution.
I think I'm close to a viable solution but if one of you kind souls would take mercy on a blind fool and point me in the right direction I'd be forever in your debt.
I solved similar problem few years ago as my bachelor and diploma thesis. I designed a Cascade, an executable structure which forms growing acyclic oriented graph. You can read about it in my paper "Self-generating Programs – Cascade of the Blocks".
The basic idea is, that each block has inputs and outputs. Initially some blocks are inserted into the cascade and inputs are connected to outputs of other blocks to form an acyclic graph. When a block is executed, it reads its inputs (cascade will pass values from connected outputs) and then the block sets its outputs. It can also insert additional blocks into the cascade and connect its inputs to outputs of already present blocks. This should be equal to your task starting another task and passing some parameters to it. Alternative to setting output to an value is forwarding a value from another output (in your case waiting for a result of some other task, so it is possible to launch helper sub-tasks).