Search code examples
amazon-ecsaws-fargate

ECS/Fargate - can I schedule a job to run every 5 minutes UNLESS its already running?


I've got an ECS/Fargate task that runs every five minutes. Is there a way to tell it to not run if the prior instance is still working? At the moment I'm just passing it a cron expression, and there's nothing in the cron/rate aws doc about blocking subsequent runs.

Conseptually I'm looking for something similar to Spring's @Scheduled(fixedDelay=xxx) where it'll run every five minutes after it finishes.

EDIT - I've created the task using cloudformation, not the cli


Solution

  • This solution works if you are using Cloudwatch Logging for your ECS application - Have your script emit a 'task completed' or 'script successfully completed running' message so you can track it later on.

    • Using the describeLogStreams function, first retrieve the latest log stream. This will be the stream that was created for the task which ran 5 minutes ago in your case.
    • Once you have the name of the stream, check the last few logged events (text printed in the stream) to see if it's the expected task completed event that your stream should have printed. Use the getLogEvents function for this.
    • If it isn't, don't launch the next task and invoke a wait or handle as needed
    • Schedule your script to run every 5 minutes as you would normally.

    API links to aws-sdk docs are below. This script is written in JS and uses the AWS-SDK (https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS.html) but you can use boto3 for python or a different lib for other languages

        const logGroupName = 'logGroupName';
        this.cloudwatchlogs = new AwsSdk.CloudWatchLogs({
           apiVersion: '2014-03-28', region: 'us-east-1'
        });
    
     // Get the latest log stream for your task's log group. 
     // Limit results to 1 to get only one stream back.
    
        var descLogStreamsParams = {
          logGroupName: logGroupName,
          descending: true,
          limit: 1,
          orderBy: 'LastEventTime'
        };
    
        this.cloudwatchlogs.describeLogStreams(descLogStreamsParams, (err, data) => {
    
          // Log Stream for the previous task run..
    
          const latestLogStreamName = data.logStreams[0].logStreamName;
    
          // Call getLogEvents to read from this log stream now..
    
          const getEventsParams = {
            logGroupName: logGroupName,
            logStreamName: latestLogStreamName,
          };
    
          this.cloudwatchlogs.getLogEvents(params, (err, data) => {
    
            const latestParsedMessage = JSON.parse(data.events[0].message); 
    
            // Loop over this to get last n messages
            // ...
          });
        });