1

I am trying to execute SWF workflow. I am running into an issue regarding state of Promise object. My code strucutre is as below:

Methods in WorkflowClientImpl.java:

  @Override
  public void doSomething() {
    new TryCatch() {

        @Override
        protected void doTry() throws Throwable {
            System.out.println("Workflow Started");
            Promise<SomeObject> someObject = activityClient.doAction(param1);
            if(someObject.isready()) {
                 boolean reDo = shouldRestartWorkflow(someObject);
                 if(reDo) {
                      Promise<Void> timer = decisionContextProvider.getDecisionContext().getWorkflowClock()
                        .createTimer(TimeUnit.MINUTES.toSeconds(5));
                      continueAsNew(timer, param1);
                 }
            }
        }

        @Override
        protected void doCatch(Throwable e) throws Throwable {
            System.err.printlnt("Error occured while workflow");
            throw new RuntimeException(e);
        }
    };
}    


@Asynchronous
private boolean shouldRestartWorkflow(@Wait Promise<SomeObject> someObject) {

    if(someObject.get().getVariable() > 1)
        return true;

    return false;
}

@Asynchronous
public void continueAsNew(Promise<Void> timer, String param1) {
    selfClient.execute(param1);
    // SelfClient is instance of TempWorkflowSelfClient
}

The above code is supposed to restart the workflow when certain conditions are met. The conditions are dependent upon values populated in instance of SomeObject returned by activity method. However the code shouldRestartWorkflow never appears to get invoked.

I tried to write a unit test for this. Below is the code:

@Before
public void setUp() throws Exception {

    trace = new ArrayList<String>();
    // Register activity implementation to be used during test run
    TempActivitiesImpl activitiesImpl = new TempActivitiesImpl(null, null) {

        @Override
        public SomeObject doAction(String randomString) {
            trace.add("Test Case - " + randomString);
            SomeObject testObject = new SomeObject();
            testObject.setVariable(true);

            return testObject;
        }
    };
    workflowTest.addActivitiesImplementation(activityImpl);    //Instance to activity class
    workflowTest.addWorkflowImplementationType(WorkflowImpl.class);
}


 @Test
public void testWorkflowExecutionCall() throws Throwable {

    WorkflowClient workflow = workflowFactory.getClient("RandomString");
    Promise<Void> promise = workflow.execute("RandomString");

    List<String> expected = new ArrayList<String>();
    expected.add("Test Case - RandomString");

    AsyncAssert.assertEqualsWaitFor("Unexpected Result", expected, trace, promise);
}

The above test case works. However if I were to remove the if(someObject.isready()) condition. I get error IllegalStateException: Not Ready. I was able to determine the error occurs when it tries to execute the shouldRestartWorkflow() call.

Am I doing something wrong? As far I understand, the shouldRestartWorkflow() should wait till the SomeObject is populated and returned by activity method before proceeding.

alwaysAStudent
  • 2,110
  • 4
  • 24
  • 47
  • I find that particular error occurs most often when AspectJ or the SWF annotations aren't set up properly. It's pretty annoying that way... – Krease Aug 24 '16 at 01:04
  • How did you identify which annotations were not setup correctly? I removed AspectJ capabilities for the project and then re-added them. Still getting same error. If I invoke the activity method just once (i.e. remove code path after first invocation of activity method), the code works. – alwaysAStudent Aug 24 '16 at 01:15
  • "How did You identify which annotations were not setup correctly?" Lots of pain. Sifting thru the docs to check and double check. SWF requiring AspectJ makes debugging it a huge pain. Sorry I can't help much more. – Krease Aug 24 '16 at 01:24
  • Use Task instead of @Asynchronous. It looks uglier, but doesn't rely on AspectJ. – Maxim Fateev Aug 24 '16 at 06:48

1 Answers1

0

The SWF annotations are not set up properly. Due to this issues @Asynchronous is not working properly.

To add AspectJ as a Java agent

  1. To open the Preferences dialog box, click Window > Preferences.
  2. Navigate to Java > Installed JREs.
  3. Select the appropriate JRE and click Edit.
  4. In the Default VM arguments box, enter the path to the installed AspectJ binary. This will be a path such as /home/user/aspectj1.7/lib/aspectjweaver.jar, depending on your operating system and on the version of AspectJ you downloaded.

On Linux, OS X, or Unix use:

-javaagent:/your_path/aspectj/lib/aspectjweaver.jar

On Windows, use a standard Windows-style path instead:

-javaagent:C:\your_path\aspectj\lib\aspectjweaver.jar

To configure AspectJ for AWS Flow Framework for Java, add an aop.xml file to the project.

  1. To add an aop.xml file
  2. In your project's src directory, add a directory named META-INF.
  3. Add a file named aop.xml to META-INF with the following contents.
<aspectj>
   <aspects>
      <!-- declare two existing aspects to the weaver -->
      <aspect name="com.amazonaws.services.simpleworkflow.flow.aspectj.AsynchronousAspect"/>
      <aspect name="com.amazonaws.services.simpleworkflow.flow.aspectj.ExponentialRetryAspect"/>
   </aspects>
   <weaver options="-verbose">
     <include within="<replaceable>MySimpleWorkflow.*</replaceable>"/>
   </weaver>
</aspectj>

The value of depends on how you name your project's packages. The above example assumes that the project's packages followed the pattern MySimpleWorkflow.*. Use a value appropriate for your own project's packages.

Nithin
  • 9,661
  • 14
  • 44
  • 67