I got all the WfTestFlow green. So now we can study the execution a bit better.
On Sun, Jan 21, 2018 at 3:28 PM, Stephane Ducasse <stepharo.s...@gmail.com> wrote: > HI cedrick > > >> To solve this « pb », just create WADynamicVariable as a subclass of >> DynamicVariable already in Pharo. > > Ok I will do it. What is important is to *share* knowledge and code. > So I changed and publish the code in my branch to make > CurrentWorkflowManager an dynamic variable. > Before I just inherited from Object. > Now we get a version that can be loaded. > > > There are also missing part for the >> export/import in XML (should be easy to fix and Max propose to give the code >> - DOMBuilder and co.) >> I tried to start a booklet with Stephane but it is too complicated right >> now. Stephane started a simpler version. > > For now saving and loading is not important. :) > > >> I put below a summary of the reflexion/discussion I had with Max. > > Thanks. > Now you should publish your code. > I would have preferred to work from a working code. Because now it is > like poking in the dark. > > Cedrick what did you get running? > > Stef > Some comments below > > >> ========= INTRO >> >> What's missing compared to the full (proprietary) solution are user >> interfaces that were web based (Seaside \+ Magritte). Also, persistence was >> achived through Omnibase. References were removed but they are stil some >> disfunctionning. Moreover, the completion of activities were mainly manual >> and achieved through web interface (web forms). They are, for now, no real >> way to introduce different kind of activities like those being >> message-based, event-based, service-based. >> >> To evolve, one has to remove all dependancies to Omnibase and >> Magritte/Seaside. >> >> There are also important design decisions to ensure WfWorkflow being a >> powerful and extensible workflow management system for Pharo. To me there >> are 2 main tasks: >> - rethink persistence (process definition and orchestration, realization) >> => persistance is essential and was central to Aare. Beside removing >> Omnibase references (and implication of WfManagedObject), some of the >> application features were very dependant on the persistence (like logging, >> tracing process evolution). All of these features are to be thing again >> considering as much as possible a loosely coupled solution. A general >> purpose storage solution like Voyage could be used. At first, in image >> storage will be used to focus on the running aspects of the library. >> - rethink interaction >> => Designing a general interaction sub-system is probably the more >> challenging tasks. Aare was web based. We want workflow to be UI agnostic. >> Moreover, we want to associate , >> remove Magritte (replace UI or build an independant system based on >> Annoucement for instance) > > > Yes I agree. Now I would like to be able to > - define a super simple workflow: I picked sequence: start -> task1 -> task2 > - execute it and script it resolution. > > I would like to understand the difference between frame and activation. > >> ========= RANDOM QUESTIONS AND ANSWER (in black me - below max) >> >> 1) >> >> The static definition of workflow is done through WfWorkflow, WfOutgoingEdge >> and WfSteps (+ WfConditions). The easy part :) > > Yes the easy part. > I started to add a test to cover his > >> >> The runtime aspect are achieved via WfActivation, WfWorkList, >> WfWorkflowHistory et WfWorkflowManager. More difficult to understand and >> make evolve. >> >> WfWorkflowHistory represents the different versions of a workflow, so it >> belongs to the static part. > > I saw and documented the interaction between a workflow history and > its workflows. > > > WfWorkflowManager managers workflow definitions >> (static) and activations (dynamic). >> WfFrame is also a part of the dynamic side, connecting activations to a >> workflow. >> Workflows are hierarchical, i.e. a step can have a sub workflow (see >> WfWorkflowLibrary>>simpleSubflow) > > Yes for now I do not want to understand this part. > >> >> 3) >> >> Going back to activations, here is my current understanding. >> >> Once a step is activated (all condition on Edges leading to are true - to >> evaluate outgoing conditions of a step, the step execution has to be >> complete first) , we get an activation instance (I’m not 100% sure how >> completion of an activity and outgoing conditions are managed). >> >> As far as I understand, a step can always be activated (e.g. manually). >> However, activating a step propagates the values of conditions on the edges >> to the next steps and their activations ("dead" or "alive"). Hence, an >> activation responds to #isAlive with true if at leat one incoming token was >> true ("alive") (see WfStep>>continueInFrame:fromStep:alive: and >> WfActivation>>isAlive). The conditions are evaluated once #complete is sent >> to the activation. >> Activation instances are created by two ways (slightly different for the >> start step), but generally they are created when a step receives tokens from >> the outgoing edges of an upstream activation (see >> WfStep>>continueInFrame:fromStep:alive:). >> >> >> On the exemple of BLActivationHistoryItem that you gave, I’m not sure if >> it’s an activation of a history item stored in the history (subclasss of >> WfHistory?). >> >> My idea was that it should represent a record for an activation (there might >> be multiple records for a single activation). So "HistoryItem" would be the >> general description of a record, of which "ActivationHistoryItem" is a >> special case for activations (I hope that makes sense). >> >> >> 4) >> Moreover I don’t see clearly the difference with a scheduler and a BP engine >> (they are at least really complementary). Do you see any ressemblance >> between Activation and ScheduledJob ? >> >> I actually would like to have a (simple) scheduler with the BP engine :) >> >> Well, it's certainly a matter of point of view. I would argue that an >> activation is something close to a "job". A "scheduled job" would be a more >> specific case of a "job", a job that is in a queue. An activation has no >> notion of scheduling but simply represents the idea of what happens when >> traversal between two nodes occurs. A scheduler would be one way of managing >> activations (WfWorklist seems pretty close to a scheduler, holding running >> and completed activations). > > > Too subtle for me. > > >> To me the scheduler right now is not really existing besides having a list >> of simultaneous/parralelized steps to realize (activated or not). Activated >> means currently being done. >> >> You're right, I think. The application that Workflow was designed for >> required manual interaction, hence there was no need for other methods of >> scheduling (e.g. by time or event). >> >> >> >> This activation role is about logging and interacting with responsible >> users. But it is more than that. It’s the actual job being done. >> >> Yes. >> >> >> >> 5) >> >> Concerning run time modification of a process. Is it true that we can modify >> a currently executed workflow (steps that are not yet activated ?) ? I think >> that is possible (an cool). When activated, it shouldn’t. Would you think it >> would be interesting to allow activations to be suspended/resume (frozen), >> cancelled ? >> >> The history of workflows consists of copies. The steps of a workflow >> reference the workflow they belong to. Therefore, while it is possible to >> modify a workflow, modifications do not impact running workflows, as the >> steps of that workflow continue to reference the previous version. The model >> suggests that it is ok to create a new version of a workflow but not to >> modify existing workflows. > > For now I would like to get a workflow running without modifying it > > >> The model does *allow* (in principle) to modify an existing workflow but I >> doubt that was the intention. > > I think that it was because else why to bother. > > However, I don't see why modifying an existing >> workflow has to be bad thing, as long as you can guarantee that only edges >> and steps are modified that have not yet been activated. That could open up >> some interesting possibilities. >> Cancellation of an activation could be very interesting. It would basically >> allow reversal of complex effects. Very nice idea! I'm not so sure though >> whether suspending makes much sense. Maybe when a step has the potential to >> take a long time for some operation. But then you may run into transaction >> problems. The nice thing about an activation at the moment is that it's >> atomic (in theory). But again, done right that could open up interesting >> possibilities. >> >> >> >> If a running process is modified, do we track its evolutions in >> WfWorkflowManager ? >> >> The modification of a workflow is indeed announced to WfWorkflowManager, >> yes. Workflow versions are stored in WfWorkflowHistory. For modifying a >> *running* workflow you will probably want to create a specific workflow >> manager for that, that does validation etc. >> >> >> >> The goal of history(s) are to log the realization of the process. But is it >> one of its aim to « replay » the process execution ? >> >> No. WfWorkflowHistory only stores the static definitions. However, the >> history of activations could be used to replay an execution (nice idea!). >> >> i.o.w., Is it more than log/report ? >> >> I think the activation history was designed as a log, the workflow history >> as a log and also as a way to undo changes. As you suggest, however, they >> could certainly be used for more things. >> >> >> I agree with the separation (WfWFManager for the run time evolution of the >> process definition => adaptation and WfActivationHistory for the trace of >> interactive/automatic step realizations information). >> >> >> #beginHistory implementation example was very helpful. I knew I missed >> something Just, as I see a MailManager (with role is obvious), is it >> something that has to be generalizable ? Like InteroperableManager ? >> MessageManager ? To get user interactions >> >> That would be very nice, yes. You're completely free to do what you like. It >> would be cool though if we could evolve the project as opposed to you >> creating a fork to your own liking. If you're game we can set up a workflow >> on github where you open pull requests against our repository. >> >> >> >> 6) I’d like to remove fully the reference and need of Omnibase and >> Magritte/seaside forms. >> >> Yes please! >> >> >> I think Omnibase is ok, even storing in image for instance. >> >> What’s more problematic to me is for user interactions (and even automatic >> interaction through program for instance). There are achieved in your >> example with seaside. It is ok but what if I’d like to do it more generally >> ? Would we use Annoucement for example ? >> >> I think that is completely open to implementation. In my eyes, Workflow >> should remain a separate library that does not enforce any kind of specific >> presentation or persistence. What's critical for that is of course the right >> kind of interface. >> Announcements would certainly be an interesting way to decouple Workflow >> from other parts of the system. >> >> >> I’d like to have an incomingMessageBox for each user and eventually >> transform these message in concrete action (user i/o) ? Or dispatch in >> JobQueues (each user being a distant worker thread). Again, the distinction >> between Scheduler and BPEngin is fuzzy to me. >> >> >> Does it make sense to you ? >> >> Yes, it does :) What I've asked myself (out of curiosity) is whether you >> want to have >> - a dedicated instance for executing workflows >> - a distributed workflow with autonomous synchronisation (parts of a >> workflow could run on every uses instance, others would need to be executed >> through agreement) >> - a partially distributed workflow with one or more managing nodes that >> control the core steps (e.g. you could designate parts of a workflow as >> independant) >> >> >> PS: some random comments on your proposals >> >> Parts of Workflow were never cleanly separated from the proprietary >> application, so there are indeed a couple of things that are missing (mostly >> #subclassResponsibility stuff etc.) >> >> >> >> - initializeDefaults is not present for steps but thats ok. >> >> >> - in #createIncoming: (doesn’t exist), I don’t get ….. => makePersistent >> asPersistentReference. You store persistentReference of steps. Is it like >> the step object itself ? I would store the step objects (as no persistance >> right now). >> >> An activity step is a specific subclass of a step. Such a step includes >> additional information such as documents, duration and user roles. I'm not >> sure why "makePersistent asPersistentReference" is sent there, as WfStep >> already inherits from WfManagedObject and would, therefore, already be >> managed by OmniBase. But I don't know OmniBase, maybe some things need to be >> announced specifically. >> >> >> - I don’t understand the offsetSeconds in your BLActivationHistoryItem >> >> That's really just some business rule to modify the timestamp of the history >> item. >> >> >> ============= Others responses from Max >> >> WfWorkflow - Load and Run >> All instances that inherit from WfManagedObject were managed by OmniBase, >> yes. >> DomBuilder is a small package for wrapping XML-Parser. I'll publish it so >> you can use it. > > Cedric did you got this package? > > > The XML-Parser package has been significantly modified and >> is now named XMLParser (you can find it in the catalog). You should make the >> changes necessary to use the current incarnation of XMLParser (decide for >> yourself whether you still need DomBuilder or not). > > But this is not really important. > >> >> >> Those IDXXX classes belong to another package a didn't publish (but will). >> This package also includes an OmniBase specific class. >> Magritte has changed significantly over the years but the core should be >> pretty much the same. Just load the newest Magritte and try working with >> that. >>> ok but avoidable ? >>> try loading Magritte ? Long … >> >> #beginInHistory should be implemented with #subclassResponsibility on >> WfActivation. >> Your explicit implementation could then look something like this: >> beginInHistory >> self history add: (MyActivationHistoryItem new >> message: 'started'; >> user: (WACurrentSession value >> ifNotNilDo: [ :session | session user ]); >> type: #started; >> yourself). >> MyMailManager noteNewActivation: self >> >> Basically, what the history contains is up to the workflow implementation. I >> think it would makes sense though to have an abstract >> WfActivationHistoryItem. >> WfActivation>>history should be implemented like this: >> history >> ^self propertyAt: #history ifAbsentPut: [ OrderedCollection new ]. >> >> Although I think that it would be good to have a dedicated >> WfActivationHistory class. WfWorkflowHistory is associated with changes to >> the workflow, not activations. Both history classes should probably inherit >> from an abstract class WFAbstractHistory. >> >> >> Seaside interaction >> >> Here are a couple of action implementations in Seaside components that >> should give you an idea of how to interact with the workflow: >> MyActivationComponent>>complete >> self activation hasCompleted >> ifTrue: [ ^ self ]. >> self history add: (BLActivationHistoryItem new >> message: 'completed'; >> user: self session user; >> type: #completed; >> offsetSeconds: -1; >> yourself). >> self activation complete. >> >> MyActivationForm>>accept: aString >> self activation authorized: true. >> self history add: (BLActivationHistoryItem new >> comment: aString; >> message: 'accepted'; >> user: self session user; >> type: #accepted; >> offsetSeconds: -2; >> yourself). >> self completeIfSatisfied. >> >> MyActivityList>>addActivity >> self call: (MyActivityEditor new >> workflow: self workflow; >> yourself). >> self refresh. >> >> MyActivityEditor>>buildActivity >> ^(self workflow newActivityStep >> initializeDefaults; >> yourself) >> asPersistentReference. >> >> MyTransitionEditor>>createIncoming >> | step | >> step := (self workflow newActivityStep >> initializeDefaults; >> yourself) makePersistent asPersistentReference. >> self addIncoming: step. >> MyCurrentWorkflowComponent value showActivity: step. >> >> MyTransitionEditor>>addIncoming: anActivity >> ^self add: anActivity to: self activity. >> >> MyTransitionEditor>>add: aSourceActivity to: aDestinationActivity >> ^aSourceActivity addOutgoingEdgeFor: aDestinationActivity. >> >> MyTransitionEditor>>editCondtions: anEdge >> | component | >> anEdge condition isTrueCondition >> ifTrue: [ anEdge condition: WfAllCondition new ]. >> component := (MyConditionEditor activity: self activity) >> container: anEdge; >> addDecoration: (MyToolbarDecoration new >> title: 'Edit Transition Conditions to: ' , anEdge to name; >> toolbar: [ :html | >> html >> icon: 'icon_close.gif' >> text: 'Close' >> action: [ component answer ]. >> html helpIconOn: component ]; >> yourself); >> yourself. >> self call: component. >> >> MyConditionEditor>>addRule: aDescription >> | new | >> new := MyCondition newPersistent >> field: aDescription; >> asPersistentReference. >> new := self call: (self >> buildEditorFor: new >> titled: 'Add Rule for ' , aDescription asLabel). >> new isNil ifFalse: [ >> self condition add: new; markDirty. >> self changedForm ]. >> >> >>> WfWorflowManager class is empty defining empty stubs/protocols. Its aim >>> seems to be about “logging/noting” changes. Is is it’s only role ? >> Correct. You would use WfWorkflowManager to update the workflow in OmniBase >> (e.g. mark dirty, add new activation etc.). #generateID would generate an ID >> from OmniBase and #activationClass would answer your specific activation >> class, if you choose to override WfActivation. >>