6

AWS PHPSDK 2+ で利用できる SWF ワークフロー PHP サンプル コードがあるかどうか疑問に思っていました。

4

2 に答える 2

13

チュートリアルを探しましたが、見つかりませんでした。最終的に、Ruby と Web API を使用してドキュメントとサンプルを調べ、PHP SDK の操作の要点をまとめました。

最初に行う必要があるのは、ドメイン、ワークフロー、およびアクティビティを登録することです。これは、AWS コンソールまたは PHP SDK を使用して実行できます。SDK を使用して、次を使用します。

<?php

require_once "path/to/aws.phar";

use Aws\Swf\SwfClient;

// Create an instance of the SWF class
$client = SwfClient::factory(array(
    "key" => "your_aws_key",
    "secret" => "your_aws_secret_key",
    "region" => "your_aws_region"
));

// Register your domain
$client->registerDomain(array(
    "name" => "domain name you want",
    "description" => "this is a test domain",
    "workflowExecutionRetentionPeriodInDays" => "7"
));

// Register your workflow
$client->registerWorkflowType(array(
    "domain" => "domain name you registered in previous call",
    "name" => "workflow name you want",
    "version" => "1.0",
    "description" => "this is a sample",
    "defaultTaskList" => array(
        "name" => "mainTaskList"
    ),
    "defaultChildPolicy" => "TERMINATE"
));

// Register an activity
$client->registerActivityType(array(
    "domain" => "domain name you registered above",
    "name" => "activity name you want",
    "version" => "1.0",
    "description" => "first activity in our workflow",
    "defaultTaskList" => array(
        "name" => "mainTaskList"
    )
));

// Follow activity registration example above and register 
// more activities as you wish

次のステップは、ディサイダーを作成することです。これは、アクティビティ (ワーカー) ノードの調整ノードとして機能するスクリプトです。

// Ask SWF for things the decider needs to know
$result = $client->pollForDecisionTask(array(
    "domain" => "your domain name",
    "taskList" => array(
        "name" => "mainTaskList"
    ),
    "identify" => "default",
    "maximumPageSize" => 50,
    "reverseOrder" => true
));

// Current version of activity types we are using
$activity_type_version = "1.0";

// Parse info we need returned from the pollForDecisionTask call
$task_token = $result["taskToken"];
$workflow_id = $result["workflowExecution"]["workflowId"];
$run_id = $result["workflowExecution"]["runId"];
$last_event = $result["events"][0]["eventId"];

// Our logic that decides what happens next
if($last_event == "3"){
    $activity_type_name = "activity to start if last event ID was 3";
    $task_list = "mainTaskList";
    $activity_id = "1";
    $continue_workflow = true;
}
elseif($last_event == "8"){
    $activity_type_name = "activity to start if last event ID was 8";
    $task_list = "mainTaskList";
    $activity_id = "2";
    $continue_workflow = false;
}

// Now that we populated our variables based on what we received 
// from SWF, we need to tell SWF what we want to do next
if($continue_workflow === true){
    $client->respondDecisionTaskCompleted(array(
        "taskToken" => $task_token,
        "decisions" => array(
            array(
                "decisionType" => "ScheduleActivityTask",
                "scheduleActivityTaskDecisionAttributes" => array(
                    "activityType" => array(
                        "name" => $activity_type_name,
                        "version" => $activity_type_version
                    ),
                    "activityId" => $activity_id,
                    "control" => "this is a sample message",
                    // Customize timeout values
                    "scheduleToCloseTimeout" => "360",
                    "scheduleToStartTimeout" => "300",
                    "startToCloseTimeout" => "60",
                    "heartbeatTimeout" => "60",
                    "taskList" => array(
                        "name" => $task_list
                    ),
                    "input" => "this is a sample message"
                )
            )
        )
    ));
}
// End workflow if last event ID was 8
else if($continue_workflow === false){
    $client->respondDecisionTaskCompleted(array(
        "taskToken" => $task_token,
        "decisions" => array(
            array(
                "decisionType" => "CompleteWorkflowExecution"
            )
        )
    ));
}

最後のステップは、アクティビティ ワーカーを作成することです。次の形式を使用してスピンアップできます。

// Check with SWF for activities
$result = $client->pollForActivityTask(array(
    "domain" => "domain name you registered",
    "taskList" => array(
        "name" => "mainTaskList"
    )
));

// Take out task token from the response above
$task_token = $result["taskToken"];

// Do things on the computer that this script is saved on
exec("my program i want to execute");

// Tell SWF that we finished what we need to do on this node
$client->respondActivityTaskCompleted(array(
    "taskToken" => $task_token,
    "result" => "I've finished!"
));

アクティビティ ワーカーとディサイダーのスクリプトは、任意のサーバーに配置できます。これらのスクリプトはすべて、相互に通信するために SWF を呼び出します。

最後に、作成したばかりのワークフローを開始するには、次を使用します。

// Generate a random workflow ID
$workflowId = mt_rand(1000, 9999);

// Starts a new instance of our workflow
$client->startWorkflowExecution(array(
    "domain" => "your domain name",
    "workflowId" => $workflowId,
    "workflowType" => array(
        "name" => "your workflow name",
        "version" => "1.0"
    ),
    "taskList" => array(
        "name" => "mainTaskList"
    ),
    "input" => "a message goes here",
    "executionStartToCloseTimeout" => "300",
    'taskStartToCloseTimeout' => "300",
    "childPolicy" => "TERMINATE"
));
于 2014-12-09T15:34:42.123 に答える
1

上記の投稿に基づいて、目的に合わせて簡単に変更できる、完全に機能するワークフローを作成することができました。ありがとうございます。composer で AWS PHP SDK をインストールし、正しいファイルパスを割り当て、コンソールでドメイン、ワークフロータイプ、およびアクティビティタイプを設定した後 (これは非常に簡単です)、以下のスクリプトを使用してフローを順番に実行できます。これを投稿する前に、自分で実行することができました。すべての設定が完了したら、ExecuteFlow.php を実行するだけで十分です。

8 つのスクリプトがここに掲載されています (心配しないでください。3 つのスクリプトは非常に短いものです)。

ExecuteFlow.php :

<?php 
//This script is used to begin a new workflow then activate the decider and workers to finish the job.
// 
//SWF scripts originally developed by ~ in April, 2018 based on the first comment in https://stackoverflow.com/questions/22765377/amazon-aws-simple-workflow-service-swf-php-samples
//
//PROGRAMMER MODIFICATIONS sections are for updates to the Steps in Workflow, the rest of SWF Workflow should be automated with these scripts.
//
// Command Reference: 
//
// https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-swf-2012-01-25.html 
//
// For Reference: 
//          Workflow Type (Name) is MainWorkflow
//          Activity Type (Names) are Step 1, Step 2, and Step 3
//    Task List for MainWorkflow is MainTaskList
//           Task List for Step 1 is TaskList1, Step 2 is TaskList2, etc.
//
//
//Software Required:
//
//Installed AWS PHP SDK
//ExecuteFlow.php
//Decider.php
//Worker.php
//DescribeExecution.php
//TerminateFlow.php
//Test.php
//Test2.php
//Test3.php



//Once it's installed using composer, this accesses the PHP AWS SDK
require_once "PHP-AWS-SDK/autoload.php";


//This grabs the client from the SDK so we can use it to do our SWF bidding.
//(Note: the version should stay synonymous with the currently packaged SDK version so it works with our code.)
$client = new Aws\Swf\SwfClient([
    'version' => '2012-01-25',
    'region'  => 'us-east-1' 
    ]);



//------------------------------------------------------------------------------
//----------------------PROGRAMMER MODIFICATIONS--------------------------------
//------------------------------------------------------------------------------

//Variables that we want to carry through the workflow
$Domain_Name='MyDomainName';
$Activity_Type_Version = "1";
$Workflow_Task_List_Name="MainTaskList";
$TotalNumberofSteps=3;
$TimeAllottedforEachStep="300"; //seconds

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------



//Clear the way for a new workflow


//How many workflows are open?
$result = $client->countOpenWorkflowExecutions([
    'domain' => $Domain_Name, 
    'startTimeFilter' => [
        'oldestDate' => 1524755000,
    ],
]);

$OpenWorkflowCount=$result["count"];


if ($OpenWorkflowCount <> 0){

//This loop terminates all the current workflows 
    for ($x = 1; $x <= $OpenWorkflowCount; $x++) {


$result = $client->listOpenWorkflowExecutions([
    'domain' => $Domain_Name, 
    'startTimeFilter' => [
        'oldestDate' => 1524755000,
    ],
]);

$OpenWorkflowID = $result["executionInfos"][0]["execution"]["workflowId"];
echo "You have an open workflow: $OpenWorkflowID.\n\n";
$WorkflowID=$OpenWorkflowID;
echo "Terminating Workflow $OpenWorkflowID...\n";
$Run_ID=$result["executionInfos"][0]["execution"]["runId"];
$Reason="Flow was terminated to clear the way for a new Workflow";
require 'TerminateFlow.php';

}

}



// Execution of the workflow begins now-----------------------------------------

// Generate a random workflow ID
$WorkflowID = mt_rand(1000, 9999);

//Turn it into a string for input to SWF
settype($WorkflowID,"string");


echo "\nRandomly Generated Workflow ID is ".$WorkflowID."\n";


//Let's get this party started.
$client->startWorkflowExecution([
    'domain' => $Domain_Name,
    'workflowId' => $WorkflowID,
    'workflowType' => [
        'name' => 'MainWorkflow',
        'version' => '1'
        ],
    'taskList' => [
        'name' => $Workflow_Task_List_Name
        ], 
    'input' => 'Starting a Workflow',
    //'executionStartToCloseTimeout' => '300',
   // 'taskStartToCloseTimeout' => '300',
   // 'childPolicy' => 'TERMINATE',
]);


echo "The workflow is now being executed!\n\n";
//echo "\nLet's ask the decider what to do next:\n";
require 'Decider.php';


//Here we will confirm completion of the workflow

 echo "Verifying Completion: \n";

$result = $client->describeWorkflowExecution([
    'domain' => $Domain_Name, 
    'execution' => [ 
        'runId' => $Run_ID,
        'workflowId' => $Workflow_ID,
    ],
]);


 $Finished = $result["executionInfo"]["closeStatus"];


 if ($Finished == 'COMPLETED')
 {
 echo "$Finished \nWe have completed the workflow!\n";
 }

 else {
  echo "$Finished \nCheck on your application.\n";
 }


 //This is the amount of time it took to run the workflow

  $WorkflowStartTimestamp=$result["executionInfo"]["startTimestamp"];
 $WorkflowEndTimestamp=$result["executionInfo"]["closeTimestamp"];
 $wfinterval = $WorkflowStartTimestamp->diff($WorkflowEndTimestamp);
    $m=$wfinterval->format('%i minute(s)');
    $s=$wfinterval->format('%s second(s)');

    echo "Running time: $m $s.\n\n";

?>

Decider.php :

<?php

//DECIDER




// What's on the agenda today boss?
$result = $client->pollForDecisionTask(array(
    "domain" => $Domain_Name,
    "taskList" => array(
        "name" => $Workflow_Task_List_Name
    ),
     "identity" => "Decider is choosing whether to continue or end the workflow",
    // "maximumPageSize" => 50,
    "reverseOrder" => true //This makes sure the events are returned in reverse order. It makes it easier to tell which event is current/most recent (helps generate $WorkflowEventID variable below).
));



// Parse info we need returned from the pollForDecisionTask call
$task_token = $result["taskToken"];
$Workflow_ID = $result["workflowExecution"]["workflowId"];
$Run_ID=$result["workflowExecution"]["runId"];
$WorkflowEventID = $result["events"][0]["eventId"];


// Our logic that decides what happens next...
//If we have x steps, we will need 3+x*6 WorkflowEventID's before sending the command to end the workflow.
//Here's where this is automatically calculated:
$CalculatedEventID=3+$TotalNumberofSteps*6;


//Below, we decide on whether to continue the workflow.
//It would be simpler to skip this section and only modify the section below, but 
//it allows us to avoid redundancy (for example, "require 'Worker.php';" below).

if($WorkflowEventID < $CalculatedEventID){
    $task_list = $Workflow_Task_List_Name;
    $continue_workflow = true;
}

elseif($WorkflowEventID == $CalculatedEventID){
    $task_list = $Workflow_Task_List_Name;
    $continue_workflow = false;
}





//------------------------------------------------------------------------------
//----------------------PROGRAMMER MODIFICATIONS--------------------------------
//------------------------------------------------------------------------------
// Now that we populated our variables based on what we received 
// from SWF, we need to tell SWF what we want to do next

// These loops assign variables the appropriate names/values for each Step based
//on the Event ID we're on. These variables are carried through to the worker.
//Variable values should be synonymous with the activity types in the SWF console.


if($continue_workflow === true){

 //Decider STEP 1---------------------------------------------------------------
    if ($WorkflowEventID == "3")

 {$Step = "Step 1";
     $Activity_Task_List_Name = "TaskList1";
     $Activity_ID = "1";
    // echo "The decider says its current Workflow ID is ".$Workflow_ID."\n\n";
 }


 //Decider STEP 2---------------------------------------------------------------  
    elseif ($WorkflowEventID == "9")

 {$Step = "Step 2";
    $Activity_ID = "2";
     $Activity_Task_List_Name = "TaskList2";
 }  

  //Decider STEP 3--------------------------------------------------------------
    elseif ($WorkflowEventID == "15")

 {$Step = "Step 3";
    $Activity_ID = "3";
     $Activity_Task_List_Name = "TaskList3";
 }  

else 
{echo "Something's Fishy\n\n";}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------




//We mark the Decision Task Complete before moving to the Worker

   $client->respondDecisionTaskCompleted(array(
        "taskToken" => $task_token,
        "decisions" => array(
            array(
                "decisionType" => "ScheduleActivityTask",
                "scheduleActivityTaskDecisionAttributes" => array(
                    "activityType" => array(
                        "name" => $Step,
                        "version" => $Activity_Type_Version
                    ),
                    "activityId" => $Activity_ID,
                    "control" => "Have a great day!",
                    // Customize timeout values
                    //"scheduleToCloseTimeout" => "360",
                    //"scheduleToStartTimeout" => "300",
                    "startToCloseTimeout" => $TimeAllottedforEachStep,
                    //"heartbeatTimeout" => "60",
                    "taskList" => array(
                        "name" => $Workflow_Task_List_Name
                    ),
                    "input" => "$Step Assigned to Worker"
                )
            )
        )
    ));


//Here we have the worker do the decider's bidding. 
     require 'Worker.php';




//The Timestamp stuff and response here can also be placed at the end of the worker script.
//They are placed here to simplify the worker script since the decider is 
//really supposed to be doing all the 'non-executing stuff' stuff. 


    $ReverseDescribeorNot=False;
    require 'DescribeExecution.php';

    $TimestampStart = $result["events"][$WorkflowEventID]["eventTimestamp"];
    $TimestampEnd   = $result["events"][$WorkflowEventID+4]["eventTimestamp"];
    $interval = $TimestampStart->diff($TimestampEnd);
    $m=$interval->format('%i minute(s)');
    $s=$interval->format('%s second(s)');


    echo $Step."/".$TotalNumberofSteps." completed in $m $s.\n\n";






 //We require the Decider here because if we do so in the Worker script, the worker script is unable to finish before being executed again above. 
 //This allows the Decider to loop back up to the top and figure out where it's at in the workflow and decide from there. 
 //Although it puts the Decider into a loop of itself, the if statements make sure it executes the correct things based on its feeback from SWF.
     require 'Decider.php';


}



// End workflow if last event ID was the final WorkflowEventID
else if($continue_workflow === false){
    $client->respondDecisionTaskCompleted(array(
        "taskToken" => $task_token,
        "decisions" => array(

            array(
                "decisionType" => "CompleteWorkflowExecution",

            ),
        )
    ));
}


?>

Worker.php :

<?php

//WORKER


//Typically, for SWF, a worker is a service, script, or person that performs a specific function. 
//For our purposes, all our workers are php scripts.
//Therefore, in order to avoid redundancy, we simply use this single script to activate our workers.
//Because developers don't want to worry about putting a "pollForActivityTask" and "respondActivityTaskCompleted" call in each of their scripts,
//we simply make those calls here and execute each script when SWF is ready for it. 


//echo "\nNow, the worker is working.\n\n";



// Check with SWF for activities
$result = $client->pollForActivityTask([
    "domain" => "Cloud Optimization",
    "taskList" => [
        "name" => $Workflow_Task_List_Name
    ]
]);


// Take out task token from the response above

$task_token = $result["taskToken"];




//------------------------------------------------------------------------------
//----------------------PROGRAMMER MODIFICATIONS--------------------------------
//------------------------------------------------------------------------------
// This is where the Worker actually executes activities

//Worker STEP 1-----------------------------------------------------------------
if ($Step == 'Step 1') {

require 'Test.php';

}

//Worker STEP 2-----------------------------------------------------------------
elseif ($Step == 'Step 2') {

require 'Test2.php';
}


//Worker STEP 3-----------------------------------------------------------------
elseif ($Step == 'Step 3') {
require 'Test3.php';
}

else 
{echo "Something's Super Duper Fishy\n\n";}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------



 //If the Activity Timed out, we'll find out here before our app explodes

 //This grabs the eventType statement associated with the current Workflow EventID

 $ReverseDescribeorNot=True;
 require 'DescribeExecution.php';
 $MightHaveTimedOut = $result["events"][1]["eventType"];



if ($MightHaveTimedOut == "ActivityTaskTimedOut")
{
    echo "\n$Step Timed Out, Cancelling Workflow...\n";
    $Reason="$Step Activity Timed Out";
    require 'TerminateFlow.php';
    exit;
}

else {

    $ResultResponse=$Step."/".$TotalNumberofSteps." completed.";
// Tell SWF that we finished what we need to do on this node
$client->respondActivityTaskCompleted(array(
    "taskToken" => $task_token,
    "result" => $ResultResponse
));


}


//echo "\nAaand now back to the decider.\n";


?>

TerminateFlow.php :

<?php

$result = $client->terminateWorkflowExecution([
    'childPolicy' => 'TERMINATE',
    'details' => $Reason,
    'domain' => $Domain_Name, // REQUIRED
    'reason' => $Reason,
    'runId' => $Run_ID,
    'workflowId' => $WorkflowID, // REQUIRED
]);

echo "Workflow $WorkflowID Terminated\n\n";

?>

DescribeExecution :

<?php



// echo "\n\nExecution History:\n\n";

$result = $client->getWorkflowExecutionHistory([
    'domain' => $Domain_Name, 
    'execution' => [ 
        'runId' => $Run_ID,
        'workflowId' => $Workflow_ID,
    ],

//     'maximumPageSize' => <integer>,
//   'nextPageToken' => '<string>',
    'reverseOrder' => $ReverseDescribeorNot,//true || false,
]);


?>

Test.php :

<?php

echo "Test.php is executing!\n";

?>

Test2.php :

<?php

echo "Test2.php is executing!\n";

?>

Test3.php :

<?php

echo "Test3.php is executing!\n";

?>

ターミナル出力

スクリプトが同じフォルダーにある限り、ファイル パスは問題になりません。幸運を!

于 2018-05-14T15:33:00.440 に答える