Index: openacs-4/contrib/packages/simulation/www/doc/workflow-extensions.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/simulation/www/doc/Attic/workflow-extensions.html,v diff -u -r1.1 -r1.2 --- openacs-4/contrib/packages/simulation/www/doc/workflow-extensions.html 12 Nov 2003 13:46:11 -0000 1.1 +++ openacs-4/contrib/packages/simulation/www/doc/workflow-extensions.html 17 Nov 2003 14:46:58 -0000 1.2 @@ -34,10 +34,10 @@
The timer will always be of the form "This action will automatically - execute x number of seconds after it becomes enabled". If it is - later un-enabled (disabled) because another action (e.g. a vote - action in the second use casae above) was executed, then the timer - will be reset. If the action later becomes enabled, the timer will start + execute x amount of time after it becomes enabled". If it is later + un-enabled (disabled) because another action (e.g. a vote action in + the second use casae above) was executed, then the timer will be + reset. If the action later becomes enabled, the timer will start anew.
@@ -51,71 +51,80 @@ changes. --create table workflow_case_timed_actions( +create table workflow_actions( ... -- The number of seconds after having become enabled the action -- will automatically execute - timeout_seconds integer + timeout interval ... );-
+ DESIGN NOTE: The 'interval' datatype is not supported in + Oracle. +
+-create table workflow_case_timed_actions( +create table workflow_case_enabled_actions( case_id integer - constraint wf_case_time_act_case_id_nn + constraint wf_case_enbl_act_case_id_nn not null - constraint wf_case_time_act_case_id_fk + constraint wf_case_enbl_act_case_id_fk references workflow_cases(case_id) on delete cascade, action_id integer - constraint wf_case_time_act_action_id_nn + constraint wf_case_enbl_act_action_id_nn not null - constraint wf_case_time_act_action_id_fk + constraint wf_case_enbl_act_action_id_fk references workflow_actions(action_id) on delete cascade, - -- the timestamp when this action fires - fire_timestamp timestamp - constraint wf_case_time_act_timeout_nn + -- the timestamp when this action will fires + execution_time timestamptz + constraint wf_case_enbl_act_timeout_nn not null, - constraint workflow_case_timed_actions_pk + constraint workflow_case_enabled_actions_pk primary key (case_id, action_id) );-
After executing an action, workflow::case::action::execute
will:
worklfow_case_timed_actions
which are no longer enabled.
+ Delete all actions from worklfow_case_enabled_actions
which are no longer enabled.
workflow_case_timed_actions
, with
+ already in workflow_case_enabled_actions
, with
fire_timestamp = current_timestamp + workflow_actions.timeout_seconds
.
+ NOTE: We need to keep running, so if another automatic action + becomes enabled after this action fires, they'll fire as well. +
+
The sweeper will find rows in
- workflow_case_timed_actions
with fire_timetsamp <
- current_timestamp
, order by fire_timstamp, and execute them.
+ workflow_case_enabled_actions
with fire_timetsamp
+ < current_timestamp
, ordered by fire_timstamp, and execute
+ them.
@@ -139,7 +148,7 @@
IS THIS DIFFERENT FROM THE TRIGGER/EVENT/WHATNOT STUFF ABOVE? +
+create table workflow_actions( + ... + child_workflow integer + constraint wf_action_child_wf_fk + references workflows(workflow_id), + ... +); +create table workflow_fsm_states( + ... + -- does this state imply that the case is completed? + complete_p boolean, + ... +); + +create table workflow_action_fsm_output_map( + action_id integer + not null + references workflow_actions(action_id) + on delete cascade, + acs_sc_impl_id integer + not null + references acs_sc_impls(impl_id) + on delete cascade, + output_value varchar(4000), + new_state integer + references workflow_fsm_states +); + +create table workflow_action_child_role_map( + parent_action_id integer + constraint wf_act_chid_rl_map_prnt_act_fk + references workflow_actions(action_id), + parent_role integer + constraint wf_act_chid_rl_map_prnt_rl_fk + references workflow_roles(role_id), + child_role integer + constraint wf_act_chid_rl_map_chld_rl_fk + references workflow_roles(role_id), + mapping_type char(40) + constraint wf_act_chid_rl_map_type_ck + check (mapping_type in + ('per_role','per_member','per_user')) +); + + +create table workflow_cases( + ... + state char(40) + constraint workflow_cases_state_ck + check (state in ('active', 'completed', + 'closed', 'canceled', 'suspended')) + default 'active', + suspended_until timestamptz, + parent_enabled_action_id integer + constraint workflow_cases_parent_fk + references workflow_case_enabled_actions(enabled_action_id) +); + +create table workflow_case_enabled_actions( + enabled_action_id integer + constraint wf_case_enbl_act_case_id_pk + primary key, + case_id integer + constraint wf_case_enbl_act_case_id_nn + not null + constraint wf_case_enbl_act_case_id_fk + references workflow_cases(case_id) + on delete cascade, + action_id integer + constraint wf_case_enbl_act_action_id_nn + not null + constraint wf_case_enbl_act_action_id_fk + references workflow_actions(action_id) + on delete cascade, + enabled_state char(40) + constraint wf_case_enbl_act_state_ck + check (enabled_state in ('enabled','completed','canceled','refused')), + -- the timestamp when this action automatically fires + fire_timestamp timestamp + constraint wf_case_enbl_act_timeout_nn + not null, + constraint wf_case_ena_act_case_act_un + primary key (case_id, action_id) +); + ++ +
enabled_state
of the row in
+ workflow_case_enabled_actions
will be set to
+ 'refused'.
+ - Some process is triggered by typically a timer on an action being - enabled. + The callbacks returning 'output' above must enumerate all the values + they can possible output (similar contruct to GetObjectType + operation on other current workflow service contracts), and the + callback itself must return one of those possible values.
++ The workflow engine will then allow the workflow designer to map + these possible output values of the callback to new states, in the + case of an FSM, or similar relevant state changes for other models. +
++ Executed when an action which was previously not enabled becomes enabled. +
-- Use cases: + Executed when an action which was previously enabled is no longer + enabled, because the workflow's state was changed by some other + action.
++ We execute the OnChildCaseStateChange callback, if any. This gets to + determine whether the parent action is now complete and should fire. +
+ ++ We provide a default implementation, which simply checks if the + child cases are in the 'complete' state, and if so, fires. +
+ ++ NOTE: What do we do if any of the child cases are canceled? Consider + the complete and move on with the parent workflow? Cancel the parent + workflow? +
+ ++ NOTE: Should we provide this as internal workflow logic or as a + default callback implementation? If we leave this as a service + contract with a default implementation, then applications can + customize. But would that ever be relevant? Maybe this callback is + never needed. +
+ ++ When the action finally fires. +
+ ++ If there's any OnFire callback defined, we execute this. +
+ +
+ If the callback has output values defined, we use the mappings in
+ workflow_action_fsm_output_map
to determine which state to
+ move to.
+
+ After firing, we execute the SideEffect callbacks and send off + notifications. +
+ ++ DESIGN QUESTION: How do we handle notifications for child cases? We + should consider the child case part of the parent in terms of + notifications, so when a child action executes, we notify those who + have requested notifications on the parent. And when the last child + case completes, which will also complete the parent action, we + should avoid sending out duplicate notifications. How? +
+ ++ Cases can be active, complete, suspended, or canceled. +
+ +
+ They start out as active. For FSMs, when they hit a state with
+ complete_p = t
, the case is moved to 'complete'.
+
+ Users can choose to cancel or suspend a case. When suspending, they + can type in a date, on which the case will spring back to 'active' + life. +
+ ++ When a parent worfklow completes an action with a sub-workflow, the + child cases that are 'completed' are marked 'closed', and the child + cases that are 'active' are marked 'canceled'. +
+ ++ The difference between 'completed' and 'closed' is that completed + does not prevent the workflow from continuing (e.g. bug-tracker + 'closed' state doesn't mean that it cannot be reopened), whereas a + closed case cannot be reactivarted (terminology confusion alert!). +
+ + + + + ++TIP Master Workflow + Model = FSM + Roles + Submitter + Voter + States + Proposed + Voting + Withdrawn + Approved + Rejected + Actions + Propose + Initial action + New state = Proposed + Vote + Enabled in state = Proposed + Role = Voter + Sub-workflow = Individual Vote + In progress state = Voting + Sub-role Voter = pparent role Voter + One sub-case per user in the Voter role + New state = Approved | Rejected + Logic = + 0 Rejects + > 0 Approvals = Approved + 2/3rds Approvals => Approved + Otherwise => Rejected + Withdraw + Enabled in state = Proposed, Voting + Role = Submitter + New state = Withdrawn + +TIP Individual Vote Workflow + Model = FSM + Roles + Voter + States + Open + Approved + Rejected + Abstained + Actions + Open + Initial action + New state = Open + Approve + Enabled in state = Open + Role = Voter + New state = Approved + Reject + Enabled in state = Open + Role = Voter + New state = Rejected + Abstain + Enabled in state = Open + Role = Voter + New state = Abstained + No Vote + Enabled in state = Open + Timeout = 7 days + New state = Abstained ++ +
+Leiden Master Workflow + Model = Dependency + Roles + Client 1 + Lawyer 1 + Partner 1 + Secretary 1 + Client 2 + Lawyer 2 + Partner 2 + Secretary 2 + Library + Actions + L1 Info Request From C2 + L1 Info Request From L2 + Dependent on = L1 Info Request From C2 + L1 Info Request From Library + + L1 Draft With S1 + Dependent on = L1 Info Request From L2, L1 Info Request From Library + L1 Send Document + Dependent on = L1 Draft With S1 + + P1 Intervenes With L1 + + L2 Info Request From C1 + L2 Info Request From L1 + Dependent on = L2 Info Request From C1 + L2 Info Request From Library + + L2 Draft With S2 + Dependent on = L2 Info Request From L1, L2 Info Request From Library + L2 Send Document + Dependent on = L2 Draft With S2 + + P2 Intervenes With L2 + + Done + Dependent on = L1 Send Document, L2 Send Document + +AskInfo-GiveInfo Loop Workflow + Roles + Informer + Recipient + States + Asked + Given + Actions + Ask Info + Initial action + New State = Asked + Give Info + Enabled in state = Asked + Role = Informer + New state = Given ++ + +