Having an issue with AWS Instance schedule.
Im trying to shutdown Instances at 2am and start them up at 8am Mon-Fri.
When i tried to do this with one Period, i get the following error:
ERROR : Begin time 08:00:00 must be earlier than end time in 02:00:00
Is there any way around this? Help would be great.
Based on AWS documentation:
The begintime and endtime fields define when the Instance Scheduler will start and stop instances. If you specify a start time only, the instance must be stopped manually. Similarly, if you specify a stop time only, the instance must be started manually. If you don’t specify either time, the solution uses the days of the week, days of the month, or months rules to start and stop instances.
One way to solve your problem is, define two periods to a schedule. One for start and another for Stop (or) Use 3rd part solutions like INVOKE Cloud. Disclaimer:- I am co-founder
The solution is to have two periods. One period begintime is 00:00 and endtime 02:00. The other period begintime 08:00 and endtime 23:59. Add them to the same schedule in the periods StringSet.
Note:
The scheduler will not try to stop the instance at 23:59 and try to start it at 00:00 because by default the scheduler "checks the state of each instance at five minute intervals which means the solution will perform start and stop actions every five minutes" as seen in the facts. The scheduler skips over the first period endtime as the second period's begintime has already begun.
Related
I need to figure out the CRON expression to trigger a Lambda that runs 1 hour before a specified date and time.
Example:
I get a specific date and time from a SNS notification, say 20th May 2022, 4 pm UTC
Now, I need to create a CRON expression for 20th May 2022, 3 pm UTC (i.e., 1 hour before the specific date and time), so that the Lambda is triggered an hour before the time.
I have gone through AWS docs and understand that I need to create a CRON expression to do this. I need help in figuring out the expression that would perform this and run only once.
There are two variants to define schedule expressions. One is rate() that juts tells it how often to run, the other is cron(), which is a cron-like syntax. The full syntax for the cron call looks like this:
cron(Minutes Hours Day-of-month Month Day-of-week Year)
So in your example you can use:
cron(0 15 20 5 ? 2022)
Note that all fields accept * as the wildcard, except the Day-of-week one, which uses ?.
To actually generate this from an SNS event, you can create another Lambda function that listens to SNS events, reads the desired timestamp, and creates a new EventBridge rule with the timestamp converted to the cron format as the ScheduleExpression. Depending on the language that you use in the Lambda, use the appropriate AWS SDK to create the EventBridge rule and target. For example, if you use Python, you can use the boto3 put_rule method and then call put_target to attach the new rule to the other Lambda function that runs the scheduled code.
Also, I believe that scheduled events are only available on the default EventBridge, not on custom ones. I know this used to be a limitation before, they might have changed it in the meantime.
I'm using Auto Scaling groups which works pretty fine with some custom rules I've set, but I also noticed that I need to set the minimum values of servers to a certain, higher, amount every first Sunday of each month (we have an increase in requests at that period).
I saw the Scheduled actions in the "Automatic scaling" tab, but it does not appear to be possible to set longer than per week, even less setting something like "every first Sunday of each months".
Is this something possible in another way ? Maybe via some Cloudwatch settings with custom "cron" tasks? I'm not sure here.
You don't need to use an external service or a Lambda to do it. You can do it in the advance tab in AutoScaling option in AWS.
For your particular case, your crontab expression would be 0 14 ? * 1#1 * See the image below, it will be triggered every first Sunday of the month.
Edit: It only works in Event bridge cron expression.
Cron expression
You can create a different timer (e.g. for lambda called every morning/hour/whatever) and scale-up the scaling group from there if its the first sunday of the month.
I have a Lambda Function that needs to be invoked biweekly on Sunday at 10am. I used the rate expression to set 14 days as the rate period. However from the official documentation, I couldn't find a way to specify the Sunday at 10AM part. How can I make that happen?
If you're looking to do this you need to use a cron expression instead for the CloudWatch event.
The cron schedule 0 10 ? * 1 * will cause the CloudWatch event to trigger every Sunday at 10 AM UTC. Be aware that regardless of your region that the cron will always evaluate in UTC so you may need to adjust the times to match your local region.
More information is available in the cron expressions documentation.
I have to implement functionality that requires delayed sending of a message to a user once on a specific date, which can be anytime - from tomorrow till in a few months from now.
All our code is so far implemented as lambda functions.
I'm considering three options on how to implement this:
Create an entry in DynamoDB with hash key being date and range key being unique ID. Schedule lambda to run once a day and pick up all entries/tasks scheduled for this day, send a message for each of them.
Using SDK Create cloudwatch event rule with cron expression indicating single execution and make it invoke lambda function (target) with ID of user/message. The lambda would be invoked on a specific schedule with a specific user/message to be delivered.
Create a step function instance and configure it to sleep & invoke step with logic to send a message when the right moment comes.
Do you have perhaps any recommendation on what would be best practice to implement this kind of business requirement? Perhaps an entirely different approach?
It largely depends on scale. If you'll only have a few scheduled at any point in time then I'd use the CloudWatch events approach. It's very low overhead and doesn't involve running code and doing nothing.
If you expect a LOT of schedules then the DynamoDB approach is very possibly the best approach. Run the lambda on a fixed schedule, see what records have not yet been run, and are past/equal to current time. In this model you'll want to delete the records that you've already processed (or mark them in some way) so that you don't process them again. Don't rely on the schedule running at certain intervals and checking for records between the last time and the current time unless you are recording when the last time was (i.e. don't assume you ran a minute ago because you scheduled it to run every minute).
Step functions could work if the time isn't too far out. You can include a delay in the step that causes it to just sit and wait. The delays in step functions are just that, delays, not scheduled times, so you'd have to figure out that delay yourself, and hope it fires close enough to the time you expect it. This one isn't a bad option for mid to low volume.
Edit:
Step functions include a wait_until option on wait states now. This is a really good option for what you are describing.
As of November 2022, the cleanest approach would be to use EventBridge Scheduler's one-time schedule.
A one-time schedule will invoke a target only once at the date and time that you specify using a valid date, and a timestamp. EventBridge Scheduler supports scheduling in Universal Coordinated Time (UTC), or in the time zone that you specify when you create your schedule. You configure a one-time schedule using an at expression.
Here is an example using the AWS CLI:
aws scheduler create-schedule --schedule-expression "at(2022-11-30T13:00:00)" --name schedule-name \
--target '{"RoleArn": "role-arn", "Arn": "QUEUE_ARN", "Input": "TEST_PAYLOAD" }' \
--schedule-expression-timezone "America/Los_Angeles"
--flexible-time-window '{ "Mode": "OFF"}'
Reference: Schedule types on EventBridge Scheduler - EventBridge Scheduler
User Guide
Instead of using DynamoDB I would suggest to use s3. Store the message and time to trigger as key value pairs.
S3 to store the date and time as key value store.
Use s3 lambda trigger to create the cloudwatch rules that would target specific lambda's etc
You can even schedule a cron to a lambda that will read the files from s3 and update the required cron for the message to be sent.
Hope so this is in line with your requirements
I am wanting to send notifications based on a user-specified time. IE, in google calendar, I can receive a text message when my task time is hit.
Is the solution to this to run a cron job, have it execute every minute and scan which users have a time equaling the current time?
Since you tagged your question with celery, I assume you have celery running. You could use the eta kwarg to apply_async() to schedule a task to run at a specific time, see here:
http://docs.celeryproject.org/en/latest/userguide/calling.html#eta-and-countdown
If you need to use a cron job, I would not check if notification_time == current_time, but rather track unsent notifications with a boolean is_sent field on the model and check for notification_time <= current_time and not is_sent. This seems to be slightly less error prone. You could also add some form of check to prevent mass-sending notifications in case your system goes down for a few hours.