This stuff is freaking awesome. Thanks so much. Daz
On Thu, Sep 19, 2013 at 5:31 PM, Marcin Erdmann <marcin.erdm...@proxerd.pl>wrote: > I think I managed to fulfill all the requirements in the implementation > I've just pushed to my fork: > https://github.com/erdi/gradle/tree/should-run-after. > > In the end I went for a simpler and what looks to be a more efficient > solution. Basically when building the execution plan I track should run > after edges that were visited and take snapshots of execution plan for any > visited task that has should run after successors. When a cycle is detected > (just like before, if we end up in a previously visited node that we > haven't yet finished processing successors for) we check if we walked > through any should run after edges. If yes then we remove that edge from > the graph, restore execution plan to the state from before visiting the > 'from node' of that edge and start processing successors of that task from > scratch. If there are no should run after edges we travelled through and we > detect a cycle then we report it. > > I'll add some docs for this over the weekend. > > Marcin > > > > On Sat, Sep 14, 2013 at 4:23 PM, Marcin Erdmann <marcin.erdm...@proxerd.pl > > wrote: > >> Hi all, >> >> I started looking into how to implement shouldRunAfter task ordering >> rule. Some time ago Adam wrote: >> >> The idea is to add a very weak task execution rule that only provides >>> hints for execution order and implies nothing else. So, if A >>> shouldRunAfterB then: >>> >>> 1. If A or B are not scheduled to run, ignore the rule. >>> 2. Run A after B only if there are no other contradictory rules on the >>> ordering of A and B. That is, ignore cycles introduced by shouldRunAfter >>> rules. >>> 3. The dependencies of A shouldRunAfter B and its dependencies. >>> 4. If B fails or is not run, A can still be run. >>> 5. If there is an idle worker thread and A is the only task whose >>> dependencies have been satisfied, then run A regardless of whether B >>> has beenrun or not. That is, prefer running the task over an idle >>> worker thread. >>> >>> Similar to mustRunAfter, but different in #2 and #5 above. >>> >> >> #1, #3 and #4 are straightforward. With regards to #2 the idea is to: >> >> - at the beginning of >> DefaultTaskExecutionPlan.determineExecutionPlan() find all cycles in the >> execution graph using CachingDirectedGraphWalker the same way as in >> onOrderingCycle() >> - find the first cycle that has no shouldRunAfter edges and throw a >> CircularReferenceException >> - if no such cycles are found iterate over all cycles and for each >> remove the first found shouldRunAfter edge (possibly with some logging?) - >> this will break the cycle; it's possible that a cycle won't have a >> shouldRunAfter edge as some cycles may share a shouldRunAfter edge that >> has >> been already removed but because we checked for cycles without >> shouldRunAfter edges before we know that all cycles in this phase had such >> edge at one point >> - continue with execution plan determination >> >> The downside here is that we would be adding another graph traversal to >> the process. On the other hand I don't see how we could detect and break >> cycles with shouldRunAfter edges in them without doing so. >> >> With regards to #5, do I understand correctly that it simply means that >> shouldRunAfter ordering should not be treated as a dependency in context of >> TaskInfo.allDependenciesComplete()? >> >> Marcin >> >> > >