1 2 3 4 5 Previous Next 60 Replies Latest reply on Dec 11, 2005 9:35 AM by chprvkmr Go to original post
      • 30. Re: Simultaneous execution of  Fork children
        sforema

        I never seem to be able to connect to that damn sorceforge cvs (grrrr!), so I may be duplicating work here. I have the alpha and don't see anything besides a stubbed out class called "ParallelSplit.java".

        After digging into the problem, it seems to me that a new class called ForkAsync could do the trick. It would simply do this portion of the logic differently:

        // phase three: launch child tokens from the fork over the given transitions
        iter = forkedTokens.iterator();
        while( iter.hasNext() ) {
        ForkedToken forkedToken = (ForkedToken) iter.next();
        Token childToken = forkedToken.token;
        String leavingTransitionName = forkedToken.leavingTransitionName;
        ExecutionContext childExecutionContext = new ExecutionContext(childToken);
        if (leavingTransitionName!=null) {
        leave(childExecutionContext, leavingTransitionName);
        } else {
        leave(childExecutionContext);
        }
        }

        The join and fork currently work together in a rather sensitive / co-operative manner. Basically the join doesn't allow a token thru until all tokens have reached the join. The join "rejectes" a token by returning. This causes the for loop of the join (above) to continue processing. I am not sure what will happen if there is no for-loop to come back to. And I am unsure of how thread safe jBPM is... we will see...

        • 31. Re: Simultaneous execution of  Fork children
          ralfoeldi

          Hi Sean,

          I think I answered some of your questions in other threads so I will pick up your 'rant' (your expression) on jBPM.

          1. Persistence: jBPM persists state. From your prior questions I understand that you have a somewhat different notion of transactional integrity. The way jBPM / Hibernate does it is the way it is supposed to be. There is absolutely NO neccessity to persist state after every node. Repeating what I already stated: jBPM executes and commits all synch actions in a single transaction. This MUST be exactly this way or else you could not bundle more then one action in a transaction and more important, you could not rollback previous actions. If you want to break up the transactions used wait states.

          2. Concurrency / parallel processing: jBPM is a state machine that implements concurrency on a business process layer. It does not manage Threads, it should not manage Threads and in an J2EE App Server it is not allowed to manage Threads. That also is the way it is supposed to be. jBPM could not be used in J2EE App servers if it started spawning Threads. (At least Websphere would actively prevent this.)

          In other words: were jBPM to implement your views of a BPM machine it would be utterly useless to any serious use in an J2EE app server.

          It really depends on what you want. There are BPMs out there that 'automagically' do all kinds of things and you don't have to think about the internals. The payoff is missing control. jBPM gives me control (well, sort of :-) but forces me to formulate and implement exactly what I want.

          I'm not sure you really have a problem. Check the scope of your transactions, then maybe you don't have the need to persist (better commit) state all the time. And if you're in a non managed environment implementing a Timer that executes nodes in a own Thread shouldn't be that much of a problem. I'm kind of in the same situation as you are on this one. See http://www.jboss.com/index.html?module=bb&op=viewtopic&t=73234

          Greetings

          Rainer

          • 32. Re: Simultaneous execution of  Fork children
            sforema

            I was afraid this was going to happen, but it took me all morning to create the test case.

            Here is the scenario:
            [img]http://static.flickr.com/20/71523252_c5116f6d9a.jpg?v=0[/img]

            If I cause both parallel1 and parallel2 to not signal and signal their respective tokens later asynchronously, the join will not work because the threads don't know about each others state. ie: if parallel2b finishes first, its hit against the join is not registered so that when parallel1b hits the join, the join allows processing thru.

            I essentially need state refreshed in the join prior to allowing its logic to execute. How do I do this?

            Once I have this nailed, I am all done with testing...

            (help)

            • 33. Re: Simultaneous execution of  Fork children
              sforema

              OK, the image didn't work and I thought I read my post thru, but I made an important typo:

              the join is NOT allowing processing thru when the parallel processing occurs in different threads.

              • 34. Re: Simultaneous execution of  Fork children
                kukeltje

                If I understand correctly http://is.tm.tue.nl/research/patterns/download/swf/pat_8.swf is what you want. Right?

                The default behaviour of a join is as you describe it, wait for all tokens to arrive.

                See the testcases in /jbpm.3/src/java.jbpm.test/org/jbpm/jpdl/patterns/Wfp08MultiMergeTest.java on how the behaviour according to the pattern can be achieved

                • 35. Re: Simultaneous execution of  Fork children
                  sforema

                  "The default behaviour of a join is as you describe it, wait for all tokens to arrive."

                  This is true, but if you are running the tokens in different threads the join doesn't know about the state from each thread.

                  To make it clearer, think of it this way: each thread is running in a different VM. The cached hibernate objects need to be refreshed at the join so that one VM knows what is going on in the other.

                  ie: when the second thread hits the join, it doesn't know that the first thread hit the join because they are using seperate instances of hibernate objects.

                  The hibernate data must be refreshed prior to executing the join logic so that the join works properly in an asynchronous environment.

                  Does that make my problem clearer?

                  Sean

                  • 36. Re: Simultaneous execution of  Fork children
                    ralfoeldi

                    Hi Sean,

                    you might have a valid problem. It's basically one of concurrency. See http://www.jboss.com/index.html?module=bb&op=viewtopic&t=73332.

                    The solution would be to lock on the processInstance... but that wouldn't be a solution.

                    Ronald? Anyone? What is the official jBPM position on this one? I don't have exactly Sean's problem right now, but I see it coming.

                    Greetings

                    Rainer

                    • 37. Re: Simultaneous execution of  Fork children
                      sforema

                      Once a process instance gets into this situation, it is interesting to try to complete it. Both tokens are now stting at the join.

                      I have learned from experience that signaling a join, fork, start, or end cause bad things to happen... If I signal either token, the process instance follows to completion, but it doesn't set the end date on the process instance. If I signal the remaining token, it runs the final steps again and then sets the end date...

                      • 38. Re: Simultaneous execution of  Fork children
                        sforema

                        If I try to close the JbpmSession and create a new one in the middle of a process running, it pukes (as expected):

                        ERROR 1208:1345 zationException : failed to lazily initialize a collection of role: org.jbpm.graph.exe.Token.children - no session or session was closed
                        org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: org.jbpm.graph.exe.Token.children - no session or session was closed
                        at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:191)
                        at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:183)
                        at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:48)
                        at org.hibernate.collection.PersistentMap.keySet(PersistentMap.java:165)
                        ... on and on ...


                        This is a problem. I can't stop a process at join and signal the token later. Joins shouldn't be signalled.

                        I don't see a way out of this situation.

                        I am starting to feel that jBPM is not capable of handling asychronous work on a single process instance.

                        I need a way to reload the tokens so that this question in the Join class answers correctly: concurrentToken.isAbleToReactivateParent()

                        Sean

                        • 39. Re: Simultaneous execution of  Fork children
                          sforema

                          I was able to come up with a workaround hack.

                          I added a state to each forked branch just prior to the join. This state fires off a thread that sleeps for 10 seconds, allowing the current thread to go into a wait state and then resignals the token for the waiting branch. This causes the the latest state information to be loaded for a correct join.

                          I need to think thru some sort of semaphore mechanism to make sure I don't land into an odd situation where one thread is saving while the other is loading, but it seems to work.

                          Sean

                          • 40. Re: Simultaneous execution of  Fork children
                            aguizar

                            Think of jBPM of a convenient way to update your process management database. Refreshing is not the approach you would normally take in an application with multiple concurrent accesses to a database. The thread would either block (pessimistic lock) or receive an exception causing it to retry its work (optimistic lock).

                            I can think of this solution: introduce a state just before the join, and perform the work in each path without locking. When that returns, lock the process instance and then signal the token. The tradeoff here is, as always, concurrency vs. consistency.

                            • 41. Re: Simultaneous execution of  Fork children
                              sidh1979

                              Hello Sean,
                              Actually we are also having the problem of async execution.
                              We went through the workaround suggested by you. Can you provide more details on the workaround.
                              If possible can you share the piece of code that you wrote.

                              thanx.

                              • 42. Re: Simultaneous execution of  Fork children
                                sforema

                                Here is the original process def:
                                http://static.flickr.com/20/71523252_c5116f6d9a.jpg?v=0

                                Here is the new process def:
                                http://static.flickr.com/20/71779978_7df2acc810.jpg?v=0

                                parallel1 and parallel2 are designed to go into wait states. I then signal their respective tokens which causes parallel1b and parallel2b to run. each waits 30 seconds before continuing, so I have time to signal the tokens.

                                Notice the inclusion of a refresh state in each branch before the join. The purpose of this state is to cause the branch to exit (no signal). Just before falling out, it fires off a thread that is designed to resignal the token. This causes the branch to continue past the refresh node with state refreshed.

                                It works. I've tested it. I was really really close to chucking jBPM completely, so this insight saved a headache on my part...

                                This code is not perfect and I intend on improving today. I want make these changes:
                                1. have the thread wake up every second checking to see if the token is finished (I think I should be able to do this).
                                2. create some sort of symaphore so that a save of state and load of state are synchronous for a process instance. Since this could happen across VMs, it will be interesting.

                                Here is the code snippet:
                                call this in the execute of a class in the node-enter of refresh:
                                Refresh r = new Refresh(context.getToken().getId());

                                This is the inner class:
                                > Note that ProcessWrapper is a convenience class I've created to do common things in jBPM without having to worry about all the details. It is normally called by a URL using jetty...

                                // Class to re-signal the token after it falls out of scope
                                private class Refresh implements Runnable {

                                private long tokenId;

                                public Refresh(long tokenId) {
                                this.tokenId = tokenId;
                                Thread t = new Thread(this);
                                t.start();
                                }

                                public void run() {

                                try {
                                // Sleep for 10 seconds (that should be more than enough for the
                                // persistance of this step to complete)
                                Thread.sleep(10000);

                                // Re-signal
                                ProcessWrapper wrapper = new ProcessWrapper();
                                log.info("about to signal token from refresh: " + tokenId);
                                wrapper.signalToken(tokenId);
                                log.info("token signaled from refresh: " + tokenId);

                                }
                                catch (Exception ex) {
                                log.error("Was unable to refresh token before join: " + tokenId);
                                }

                                }

                                }

                                • 43. Re: Simultaneous execution of  Fork children
                                  sforema

                                  Alejandro : When you say "lock the process instance", are you saying:

                                  hibernateSession = jbpmSession.getSession;
                                  jbpmObject = lookupJbpmObjectYouWantToWorkOn(...);
                                  hibernateSession.lock(jbpmObject , LockMode.UPGRADE);

                                  I found this in discussion thread:
                                  http://www.jboss.com/?module=bb&op=viewtopic&t=72556

                                  • 44. Re: Simultaneous execution of  Fork children
                                    chprvkmr

                                    HI Sean,

                                    parallel1 and parallel2 are designed to go into wait states. I then signal their respective tokens which causes parallel1b and parallel2b to run. each waits 30 seconds before continuing, so I have time to signal the tokens.


                                    Can you elaborate on that. If possible provide code snippet.