2016-09-22 64 views
1

現狀:AWS簡單工作流服務 - 運行長時間運行可靠

我想使用AWS SWF協調長時間運行的人工活動。當AWS中的活動正在計劃中時,我將其轉移到數據庫以在UI上顯示哪些任務正在等待處理。這些任務可能需要數週才能完成,因此它們在SWF中有很長的超時時間。

問題:

如果我的應用程序無法填充DB(掛起或死亡,沒有報告任何錯誤),則任務不會被人看到,然後重試可以周後纔會發生,活動時候出(這顯然是不可接受的)。

問:

所以我希望有「啓動」任務的能力(有說30秒超時),當應用程序是確保活動現在開始設置超時周。使用SWF優雅地完成它真的有可能嗎?

(我已經通過doc和幾個例子看,仍然不明白什麼是運行的手動任務的設想方式)

回答

3

不幸的是,SWF服務不支持「啓動活動任務」 API調用。我使用的解決方法是使用短超時的活動將記錄插入到數據庫中。然後根據手動任務完成信號工作流程。需要一個單獨的計時器來處理手動任務超時。所有這些邏輯都可以封裝在一個單獨的類中供重用。

使用信號增加的好處是手動任務通常具有多個狀態。例如,工作流可以在任務被聲明並且隨後被釋放時發信號通知。每個狀態可以有不同的超時時間。

[編輯:添加稻草人ManualActivityClient示例]

public class ManualActivityClient { 

    private final Map<String, Settable<Void>> outstandingManualActivities = new HashMap<>(); 

    private StartManualActivityClient startActivityClient; 
    private WorkflowClock clock; 

    public Promise<Void> invoke(String id, String activityArgs, long timeout) { 
     Promise<Void> started = startActivityClient.start(id, activityArgs); 
     Settable<Void> completionPromise = new Settable<>(); 
     outstandingManualActivities.put(id, completionPromise); 
     // TryFinally is used to define cancellation scope for automatic timer cancellation. 
     new TryFinally() { 
      @Override 
      protected void doTry() throws Throwable { 
       // Wrap timer invocation in Task(true) to give it daemon flag. Daemon tasks are automatically 
       // cancelled when all other tasks in the same scope (defined by doTry) are done. 
       new Task(true) { 
        @Override 
        protected void doExecute() throws Throwable { 
         Promise<Void> manualActivityTimeout = clock.createTimer(timeout); 
         new Task(manualActivityTimeout) { 
          @Override 
          protected void doExecute() throws Throwable  { 
           throw new TimeoutException("Manual activity " + id + " timed out"); 
          } 
         }; 
        } 
       }; 
       // This task is used to "wait" for manual task completion. Without it the timer would be 
       // immediately cancelled. 
       new Task(completionPromise) { 
        @Override 
        protected void doExecute() throws Throwable { 
         // Intentionally empty 
        } 
       }; 
      } 

      @Override 
      protected void doFinally() throws Throwable { 

      } 
     }; 
     return completionPromise; 
    } 

    public void signalManualActivityCompletion(String id) { 
     // Set completionPromise to ready state 
     outstandingManualActivities.get(id).set(null); 
    } 
} 

這個類可以作爲:

@Workflow(...) 
public class ManualActivityWorkflow { 

    private ManualActivityClient manualActivityClient; 

    @Execute(...) 
    public void execute() { 
     // ... 
     Promise<Void> activity1 = manualActivityClient.invoke("activity1", "someArgs1", 300); 
     Promise<Void> activity2 = manualActivityClient.invoke("activity2", "someArgs2", 300); 

     // ... 
    } 

    @Signal(...) 
    public void signalManualActivityCompletion(String id) { 
     manualActivityClient.signalManualActivityCompletion(id); 
    } 

}

+0

感謝偉大的答案!不幸的是,我發現這種解決方法不便於我的情況,因爲使用定時器+信號很難協調多個並行手動過程。 –

+0

它並不複雜,可以封裝在一個明確定義的類中。如果您在實施過程中需要幫助,請直接與我聯繫。 –

+0

我意識到我需要發送一個手動任務的定時器ID,並以這種方式協調定時器取消,因此可以協調多個手動活動。 –