简体   繁体   English

AWS Simple工作流程通知技术

[英]AWS Simple workflow notification technique

I'm new to AWS SWF and my task is to give notification(thru email) when an activity fails during first attempt ONLY. 我是AWS SWF的新手,我的任务是仅在首次尝试期间活动失败时发出通知(通过电子邮件)。 I'm using Settable<Boolean> as my flag but the value is not reliable because the workflow is running async. 我使用Settable<Boolean>作为我的标志,但是该值不可靠,因为工作流正在异步运行。 Here's my code: 这是我的代码:

 final AsyncExecutor asyncExecutor = new AsyncRetryingExecutor(retryPolicy, workflowClock);
 final Settable<Boolean> notifyException = new Settable<>();

    new TryCatch() {
        @Override
        protected void doTry() throws Throwable {
            asyncExecutor.execute(() -> new TryCatch() {
                @Override
                protected void doTry() throws Throwable {
                    Promise<ActivityOne> activityOne = activityOneClient.performAction(activityOneRequest);
                }

                @Override
                protected void doCatch(Throwable e) throws Throwable {
                    if (!notifyException.isReady()) {
                        // PERFORM notification service here!!
                        notifyException.set(true);
                    } else {
                        // DO NOTHING. Notification is already sent the first time :)
                    }

                    throw e;
                }
            });
        }

        @Override
        protected void doCatch(Throwable e) throws Throwable {
            System.out.println("======");
            System.out.println("CATCH ALL!! " + e.getMessage());
            System.out.println("======");
        }
    };

The notifyException 's value is always changing even though I explicitly set its value to true inside if statement . 即使我在if statement中将其值显式设置为truenotifyException的值始终在变化。 The result of my code is it will perform more than 1 the notification service . 我的代码的结果是它将执行多个notification service

====UPDATE=== ====更新===

 final AsyncExecutor asyncExecutor = new AsyncRetryingExecutor(retryPolicy, workflowClock);
 final Settable<Boolean> notifyException = new Settable<>();

    new TryCatch() {
        @Override
        protected void doTry() throws Throwable {
            asyncExecutor.execute(() -> new TryCatch() {
                @Override
                protected void doTry() throws Throwable {
                    Promise<ActivityOne> activityOne = activityOneClient.performAction(activityOneRequest);
                }

                @Override
                protected void doCatch(Throwable e) throws Throwable {
                    if (!notifyException.isReady()) {
                        activityOneClient.notify();
                        notifyException.set(true);
                    }
                    throw e;
                }
            });
        }

        @Override
        protected void doCatch(Throwable e) throws Throwable {
            System.out.println("======");
            System.out.println("CATCH ALL!! " + e.getMessage());
            System.out.println("======");
        }
    };

When I re-throw the exception, the activityOneClient.notify() will only be executed on the last retry of asyncExecutor , so if I dont re-throw, the activityOneClient.notify() will be executed automatically. 当我重新抛出异常时,仅在上一次重试asyncExecutor时才执行activityOneClient.notify() ,因此,如果我不重新抛出asyncExecutor ,则将自动执行activityOneClient.notify() I just need to notify if an exception occur for the first time. 我只需要通知是否第一次发生异常。

the code looks okay-ish (haven't run it). 代码看起来还不错(没有运行)。

your problem is somewhere else. 你的问题在别的地方。 the way the flow framework works is that every time there is some work to do the workflow workers or the activity workers pick up the task, run it and report back the results. 流框架的工作方式是,每当有工作要做时,工作流工作人员或活动工作人员就会接任务,运行任务并报告结果。 reporting back the results means that the result of the execution is captured in the workflow history. 报告结果意味着在工作流历史记录中捕获执行结果。

whenever the history changes the decider (workflow) worker runs and makes a decision to what should happen next. 每当历史记录更改时,决策者(工作流)工作人员就会运行,并决定下一步应该做什么。 under the covers the decider just replays all the history and makes all the decisions from the beginning of time. 在幕后,决策者仅重播所有历史并从一开始就做出所有决策。 now, it the decisions match what's in the history the decider just goes on until it hits something new. 现在,决策与决策者所经历的历史相匹配,直到决策达到新的水平为止。

simple example. 简单的例子。 say you have a workflow that has 3 steps: 假设您的工作流程包含3个步骤:

  • activity1 活动1
  • activity2 - depends on result of activity1 活动2-取决于活动1的结果
  • activity3 - depends on result of activity2 活动3-取决于活动2的结果

[ keep in mind that multiply activities can run at the same time, and if there isn't a link between output of an activity and input into the other the flow framework will move ahead and schedule multiple things in parallel. [请记住,多个活动可以同时运行,并且如果一个活动的输出与另一个活动的输入之间没有链接,则流程框架将继续前进并并行安排多个事务。 keeping it simple so that you get the idea ] 保持简单,以便您理解

at T0 when the workflow starts there is no history, the decider runs and activity1 is scheduled. 在T0处,当工作流程开始时,没有历史记录,决策者运行,并且调度activity1。

at T1 the activity1 workers pick up the task, execute it and report the result. 在T1,活动1的工作人员接任务,执行任务并报告结果。

at T2 as a result of activity1 updating history the decider is scheduled and runs + it reads the history. 由于activity1更新历史记录,因此在T2处,决策者被调度并运行+读取历史记录。 it sees activity1 should run, it sees it in the history, it sees that it completed, it schedules activity2 它看到activity1应该运行,在历史记录中看到它,看到它完成了,并计划activity2

at T3 the activity2 workers pick up the task, execute it and report the result. 在T3,活动2的工作人员接任务,执行任务并报告结果。

at T4 as a result of activity2 updating history the decider is scheduled and runs + it reads the history. 由于activity2更新了历史记录,因此在T4处,决策者被调度并运行+读取历史记录。 it sees activity1 should run, it sees it in the history, it sees that it completed. 它看到activity1应该运行,在历史记录中看到它,并且看到它已经完成。 it now sees that activity2 should run, it sees it in the history, it sees that it's completed and move on to activity3. 现在,它看到activity2应该运行,在历史记录中看到它,看到它已经完成并继续进行到activity3。 it schedules activity3. 它安排活动3。

and so on. 等等。

your problem is that the code in the decider that dictates the flow is run every time the decider runs (every decision). 您的问题是,每次决策程序运行时,决策程序中指示流程的代码都会运行 (每个决策)。 so when the decider reaches that activity it will see that it has run and has thrown and exception and it will go though the code that sets the flag + sends the email. 因此,当决策者进行该活动时,将看到它已经运行,引发了异常,并且将通过设置标志+的代码发送电子邮件。

when the exponential retries kick is, the flag will be set, but the code that sends the email will be run on every decision (the decider is basically stateless and the state is built based on the history). 当指数重试启动时,将设置标志,但是发送电子邮件的代码将在每个决策上运行(决策程序基本上是无状态的,并且状态是基于历史记录构建的)。

what you could do in this particular case is to move the part that sends the email in its own activity. 在这种情况下,您可以做的是移动发送电子邮件的部分。 this way the decider will see it in the history and fast forward instead of running it each time. 这样,决策者将在历史记录中看到它并快速前进,而不是每次都运行它。

To notify only the first exception thrown, what I did is: 仅通知第一个引发的异常,我所做的是:

@Override
    protected void doTry() throws Throwable {
        asyncExecutor.execute(() -> new TryCatchFinally() {

            Throwable throwable = null;
            @Override
            protected void doTry() throws Throwable {
                Promise<ActivityOne> activityOne = activityOneClient.performAction(activityOneRequest);
            }

            @Override
            protected void doCatch(Throwable e) throws Throwable {
                if (!notifyException.isReady()) {
                    activityOneClient.notify();
                    notifyException.set(true);
                }
                throwable = e;
            }

            @Override
            protected void doFinally() throws Throwable {
                if (throwable != null) {
                    throw throwable;
                }
            }
        });
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM