{"id":15490642,"url":"https://github.com/sammarks/cloudformation-scheduled-tasks","last_synced_at":"2026-01-06T23:34:54.041Z","repository":{"id":38402660,"uuid":"200735847","full_name":"sammarks/cloudformation-scheduled-tasks","owner":"sammarks","description":"AWS CloudFormation template for triggering SNS-compatible AWS events at a specific time.","archived":false,"fork":false,"pushed_at":"2023-12-26T20:47:17.000Z","size":1946,"stargazers_count":0,"open_issues_count":18,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-19T09:19:28.783Z","etag":null,"topics":["aws","aws-cloudformation","aws-lambda","scheduled-tasks","serverless"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sammarks.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-08-05T22:12:13.000Z","updated_at":"2022-02-04T16:02:36.000Z","dependencies_parsed_at":"2023-12-26T21:49:00.627Z","dependency_job_id":null,"html_url":"https://github.com/sammarks/cloudformation-scheduled-tasks","commit_stats":{"total_commits":49,"total_committers":2,"mean_commits":24.5,"dds":0.04081632653061229,"last_synced_commit":"6fda2df2ae7d6adc820d5b07d613ea86f972daa5"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sammarks%2Fcloudformation-scheduled-tasks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sammarks%2Fcloudformation-scheduled-tasks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sammarks%2Fcloudformation-scheduled-tasks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sammarks%2Fcloudformation-scheduled-tasks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sammarks","download_url":"https://codeload.github.com/sammarks/cloudformation-scheduled-tasks/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246061878,"owners_count":20717519,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","aws-cloudformation","aws-lambda","scheduled-tasks","serverless"],"created_at":"2024-10-02T07:22:52.072Z","updated_at":"2026-01-06T23:34:53.978Z","avatar_url":"https://github.com/sammarks.png","language":"JavaScript","funding_links":["https://paypal.me/sammarks15"],"categories":[],"sub_categories":[],"readme":"![][header-image]\n\n[![CircleCI](https://img.shields.io/circleci/build/github/sammarks/cloudformation-scheduled-tasks/master)](https://circleci.com/gh/sammarks/cloudformation-scheduled-tasks)\n[![Coveralls](https://img.shields.io/coveralls/sammarks/cloudformation-scheduled-tasks.svg)](https://coveralls.io/github/sammarks/cloudformation-scheduled-tasks)\n[![Dev Dependencies](https://david-dm.org/sammarks/cloudformation-scheduled-tasks/dev-status.svg)](https://david-dm.org/sammarks/cloudformation-scheduled-tasks?type=dev)\n[![Donate](https://img.shields.io/badge/donate-paypal-blue.svg)](https://paypal.me/sammarks15)\n\n`cloudformation-scheduled-tasks` is an AWS CloudFormation template generated using the\n[Serverless Framework](https://serverless.com) designed to trigger any SNS-compatible AWS\nevent (Lambda function, Email, Text Message, etc) at a specific time.\n\n## Get Started\n\nIt's simple! Click this fancy button:\n\n[![Launch Stack](https://s3.amazonaws.com/cloudformation-examples/cloudformation-launch-stack.png)](https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/new?stackName=scheduled-tasks\u0026templateURL=https://sammarks-cf-templates.s3.amazonaws.com/scheduled-tasks/template.yaml)\n\nThen give the stack a name, and configure it:\n\n| Parameter | Default Value | Description |\n| --- | --- | --- |\n| PollingSchedule | `rate(5 minutes)` | The CloudWatch ScheduleExpression defining the interval the polling Lambda runs at. |\n| ReadCapacityUnits | 1 | The read capacity units for the Scheduled Tasks DynamoDB table. |\n| WriteCapacityUnits | 1 | The write capacity units for the Scheduled Tasks DynamoDB table. |\n| DestinationArns | | A comma-separated list of possible destination SNS topic ARNS for permissioning the polling Lambda. |\n\nFinally, reference the outputs inside another stack, or in your code:\n\n| Output | Description |\n| --- | --- |\n| IngestSNSTopicArn | The ARN of the ingest SNS topic. Read below for what data to send to this. |\n\nOnce the stack is deployed, send a new message to the SNS topic to schedule a task:\n\n```js\nsns.publish({\n  TopicArn: process.env.INGEST_TOPIC_ARN,\n  Message: JSON.stringify({\n    executeTime: moment().add(1, 'hour').unix(),\n    taskId: 'achieve-world-peace-today',\n    topicArn: 'arn:aws:sns:us-east-1:123456789:achieve-world-peace',\n    payload: {\n      when: moment().format()\n    }\n  })\n})\n```\n\nYou can also update a task to execute at a new time or with a different payload by sending it again:\n\n```js\nsns.publish({\n  TopicArn: process.env.INGEST_TOPIC_ARN,\n  Message: JSON.stringify({\n    executeTime: moment().add(1, 'hour').add(1, 'day').unix(),\n    taskId: 'achieve-world-peace-today',\n    topicArn: 'arn:aws:sns:us-east-1:123456789:achieve-world-peace',\n    payload: {\n      when: moment().add(1, 'day').format()\n    }\n  })\n})\n```\n\nYou can delete a task by passing a falsy `executeTime`:\n\n```js\nsns.publish({\n  TopicArn: process.env.INGEST_TOPIC_ARN,\n  Message: JSON.stringify({\n    executeTime: null,\n    taskId: 'achieve-world-peace-today'\n  })\n})\n```\n\n### Usage in Another Stack or Serverless\n\nAdd something like this underneath resources:\n\n```yaml\nsubscriptionExpiredTopic:\n  Type: AWS::SNS::Topic\n  Properties: {}\notherTopic:\n  Type: AWS::SNS::Topic\n  Properties: {}\nscheduledTasksStack:\n  Type: AWS::CloudFormation::Stack\n  Properties:\n    TemplateURL: https://sammarks-cf-templates.s3.amazonaws.com/scheduled-tasks/VERSION/template.yaml\n    Parameters:\n      PollingSchedule: 'rate(5 minutes)'\n      ReadCapacityUnits: 1\n      WriteCapacityUnits: 1\n      DestinationArns:\n        'Fn::Join':\n          - ','\n          - - Ref: subscriptionExpiredTopic\n          - - Ref: otherTopic\n```\n\nAnd then when you want to reference the ingest topic in your environment variables:\n\n```yaml\nenvironment:\n  SCHEDULED_TASK_INGEST:\n    Fn::GetAtt:\n      - scheduledTasksStack\n      - 'Outputs.IngestSNSTopicArn'\n```\n\n**Note:** This stack will require the `CAPABILITY_AUTO_EXPAND` capability when deploying\nthe parent stack with CloudFormation. If you are using the Serverless framework, you can\n\"trick\" it into adding the required capabilities by adding this to your `serverless.yaml`:\n\n```yaml\nresources:\n  Transform: 'AWS::Serverless-2016-10-31' # Trigger Serverless to add CAPABILITY_AUTO_EXPAND\n  Resources:\n    otherResource: # ... all of your original resources\n```\n\n**A quick note on regions:** If you are deploying this stack in a region other than `us-east-1`,\nyou need to reference the proper region S3 bucket as we're deploying Lambda functions. Just\nadd the region suffix to the template URL, so this:\n\n```\nhttps://sammarks-cf-templates.s3.amazonaws.com/scheduled-tasks/VERSION/template.yaml\n```\n\nbecomes this:\n\n```\nhttps://sammarks-cf-templates-us-east-2.s3.amazonaws.com/scheduled-tasks/VERSION/template.yaml\n```\n\n### What's deployed?\n\n- Two Lambda Functions (Schedule and Ingest)\n- A DynamoDB table (with configurable provisioned capacity)\n- A SNS Topic\n- IAM Permissions for the Schedule Lambda\n\n### How does it work?\n\nThe best way to describe this is to go through what each lambda function is responsible for:\n\n#### ingest\n\nThe Ingest Lambda is responsible for processing incoming messages from the ingest SNS topic.\nIf a new message comes in with a truthy `executeTime`, it updates the scheduled tasks table\ninside DynamoDB with the passed payload, topic ARN, and execution time (in unix time, seconds).\n\nIf the `executeTime` is falsy, it attempts to delete the existing record from DynamoDB so it\nis not executed.\n\n#### schedule\n\nThe Schedule Lambda is run periodically (you can configure the interval in the stack parameters).\nWhen it runs, it queries the scheduled tasks table in DynamoDB for any execution times less than\nthe current time. If it finds any, it sends a message to their topic ARN containing the payload,\nand then deletes the item from the table. If the SNS posting fails, it leaves the item in the\ntable to be processed later.\n\n### A note on duplicate calls\n\n_It is possible_ under some less-than-ideal circumstances for an SNS message to be sent out twice\nfor the same execution. Currently this will only happen if the initial message is sent out correctly,\nbut then removing the record from DynamoDB fails.\n\n**Please write your messaging handling code to respond to duplicates and ignore them.**\n\n### Accessing Previous Versions \u0026 Upgrading\n\nEach time a release is made in this repository, the corresponding template is available at:\n\n```\nhttps://cloudformation-scheduled-tasks.s3.amazonaws.com/VERSION/template.yaml\n```\n\n**On upgrading:** I actually _recommend_ you lock the template you use to a specific version.\nThen, if you want to update to a new version, all you have to change in your CloudFormation\ntemplate is the version and AWS will automatically delete the old stack and re-create the\nnew one for you.\n\n## Features\n\n- Schedule Lambda functions to be run at a certain time through the use of an SNS topic.\n- Schedule other AWS SNS-compatbiles as well.\n- Update or cancel existing tasks by using their user-defined unique identifier.\n- Because it's all through SNS and DynamoDB, the entire functionality is self-contained within this\n  CloudFormation template.\n- Deploy with other CloudFormation-compatible frameworks (like the Serverless framework).\n\n## Why use this?\n\nRight now Lambda supports executing functions at an interval _very well._ It unfortunately does not\nsupport running tasks at a specific time very well.\n\nSuppose you have built your own subscription system, and you need to keep track of when subscriptions\nare about to expire, have expired, or are currently expiring. Since the only data you have stored is\n_when_ the subscription expires, it makes sense to automatically create a \"scheduled task\" whenever\nupdating that expiration date that schedules the actions you would like to take on the expiration\nof the subscription.\n\nSure, you could also roll your own solution to this, but why do that when there is a ready-to-deploy\nsolution already out there?\n\n[header-image]: https://raw.githubusercontent.com/sammarks/art/master/cloudformation-scheduled-tasks/header.jpg\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsammarks%2Fcloudformation-scheduled-tasks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsammarks%2Fcloudformation-scheduled-tasks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsammarks%2Fcloudformation-scheduled-tasks/lists"}