This content originally appeared on DEV Community and was authored by Bassem Hussein
Many applications need to perform tasks on a recurring schedule — refreshing data, syncing APIs, or cleaning up records. Instead of managing EC2 cron jobs or containers, AWS gives you a fully managed option: Amazon EventBridge Scheduler.
In this post, we’ll build a simple proof of concept (POC) showing how to trigger a .NET Lambda function on a schedule using AWS CloudFormation.
We’ll also discuss what to do if your job takes longer than the Lambda time limit of 15 minutes.
🧩 What You’ll Build
You’ll deploy:
- A .NET 8 Lambda function that simulates fetching stock prices
- A CloudFormation template that defines:
- The Lambda function and its IAM role
- An EventBridge Scheduler that runs every 10 minutes
- An SQS Dead Letter Queue (DLQ) for failed invocations
Here’s the architecture:
⚙️ Step 1. Create a .NET Lambda Function
Start by creating a simple .NET 8 Lambda that logs a simulated stock price.
đź§± Project Setup
dotnet new lambda.empty-function -n StockPriceUpdater
cd StockPriceUpdater
đź§ Function Code (Function.cs)
using System.Text.Json;
using Amazon.Lambda.Core;
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace StockPriceUpdater;
public class ScheduledJobInput
{
public string JobType { get; set; } = string.Empty;
public object? Payload { get; set; }
}
public class Payload
{
public string AccountCode { get; set; } = string.Empty;
}
public class Function
{
public async Task InvokeAsync(ScheduledJobInput input, ILambdaContext context)
{
context.Logger.LogLine($"[StockPriceUpdater] Triggered for JobType: {input.JobType}");
if (input.Payload is JsonElement payloadJson)
{
var payload = payloadJson.Deserialize<Payload>();
context.Logger.LogLine($"AccountCode: {payload?.AccountCode}");
}
await UpdateStockPricesAsync(input.JobType);
}
private Task UpdateStockPricesAsync(string jobType)
{
var price = Math.Round(new Random().NextDouble() * 100, 2);
Console.WriteLine($"[{jobType}] Simulated stock price: ${price} at {DateTime.UtcNow:O}");
return Task.CompletedTask;
}
}
This function accepts a small JSON payload and logs a random “stock price.”
It’s a simple stand-in for any periodic background task you might need.
📜 Step 2. Deploy with CloudFormation
Save the following as stock-price-updater.yml:
AWSTemplateFormatVersion: '2010-09-09'
Description: Lambda triggered by EventBridge Scheduler for periodic stock updates
Parameters:
ResourcePrefix:
Type: String
Default: stock-updater
LambdaCodeBucket:
Type: String
Description: S3 bucket where Lambda zip is stored
LambdaCodeKey:
Type: String
Description: Key (file name) of Lambda zip in S3
Resources:
##################################################
# IAM Role for Lambda
##################################################
StockPriceUpdaterRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${ResourcePrefix}-lambda-role"
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
##################################################
# Lambda Function
##################################################
StockPriceUpdaterFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub "${ResourcePrefix}-function"
Handler: StockPriceUpdater::StockPriceUpdater.Function::InvokeAsync
Role: !GetAtt StockPriceUpdaterRole.Arn
Runtime: dotnet8
Timeout: 600 # 10 minutes (max is 900 = 15 minutes)
MemorySize: 512
Code:
S3Bucket: !Ref LambdaCodeBucket
S3Key: !Ref LambdaCodeKey
##################################################
# Dead Letter Queue (DLQ)
##################################################
StockPriceUpdaterDLQ:
Type: AWS::SQS::Queue
Properties:
QueueName: !Sub "${ResourcePrefix}-dlq"
MessageRetentionPeriod: 1209600 # 14 days
##################################################
# Role for EventBridge Scheduler
##################################################
SchedulerInvokeRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${ResourcePrefix}-scheduler-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service: "scheduler.amazonaws.com"
Action: "sts:AssumeRole"
Policies:
- PolicyName: SchedulerInvokeLambdaAndDLQ
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action: "lambda:InvokeFunction"
Resource: !GetAtt StockPriceUpdaterFunction.Arn
- Effect: "Allow"
Action: "sqs:SendMessage"
Resource: !GetAtt StockPriceUpdaterDLQ.Arn
##################################################
# EventBridge Scheduler
##################################################
StockPriceUpdaterSchedule:
Type: AWS::Scheduler::Schedule
Properties:
Name: !Sub "${ResourcePrefix}-scheduler"
Description: "Triggers the Lambda every 10 minutes"
FlexibleTimeWindow:
Mode: "OFF"
ScheduleExpression: "rate(10 minutes)"
State: "ENABLED"
Target:
Arn: !GetAtt StockPriceUpdaterFunction.Arn
RoleArn: !GetAtt SchedulerInvokeRole.Arn
DeadLetterConfig:
Arn: !GetAtt StockPriceUpdaterDLQ.Arn
Input: |
{
"JobType": "StockUpdate",
"Payload": { "AccountCode": "Primary" }
}
Outputs:
LambdaFunctionName:
Value: !Ref StockPriceUpdaterFunction
Description: Name of the Lambda function
🚀 Step 3. Package and Deploy
- Package the Lambda
dotnet lambda package --output-package ./StockPriceUpdater.zip
aws s3 cp ./StockPriceUpdater.zip s3://your-bucket/
- Deploy the stack
aws cloudformation deploy \
--template-file stock-price-updater.yml \
--stack-name StockPriceUpdater \
--capabilities CAPABILITY_IAM \
--parameter-overrides \
ResourcePrefix=stock-updater \
LambdaCodeBucket=your-bucket \
LambdaCodeKey=StockPriceUpdater.zip
đź§ľ Step 4. Verify It Works
After deployment:
- Go to Amazon EventBridge → Scheduler → Schedules — you’ll see one schedule.
- Open CloudWatch Logs for your Lambda and verify logs every 10 minutes:
[StockPriceUpdater] Triggered for JobType: StockUpdate
AccountCode: Primary
[StockUpdate] Simulated stock price: $74.82 at 2025-10-27T09:00:00Z
Failures are sent automatically to the DLQ (SQS).
⚠️ Lambda Execution Time Limit (15 Minutes)
AWS Lambda has a hard timeout limit of 15 minutes per execution.
If your background job might exceed this:
- Step Functions: Chain multiple Lambdas or tasks with retries and parallel steps.
- AWS Fargate: Run containerized tasks without worrying about execution time.
- AWS Batch: Run large-scale batch jobs with automatic compute scaling.
For long-running tasks, replace Lambda with Step Functions, Fargate, or Batch triggered by EventBridge Scheduler.
đź§ Wrapping Up
You learned how to:
- Use EventBridge Scheduler to trigger a .NET Lambda periodically
- Handle failures with an SQS DLQ
- Deploy everything with CloudFormation
This approach is serverless, scalable, and fully managed, ideal for background jobs, periodic updates, or monitoring tasks.
âś… Key Takeaways
| Feature | Description |
|---|---|
| EventBridge Scheduler | Replaces cron jobs with a managed scheduler |
| Lambda | Ideal for short, frequent tasks |
| DLQ (SQS) | Captures failed events for later inspection |
| CloudFormation | Declarative, repeatable deployments |
| Limit | Max Lambda duration = 15 minutes — use Step Functions, Fargate, or Batch for longer jobs |
This content originally appeared on DEV Community and was authored by Bassem Hussein
Bassem Hussein | Sciencx (2025-10-27T21:35:10+00:00) đź•’ Automating Periodic Tasks with EventBridge Scheduler, .NET, and CloudFormation. Retrieved from https://www.scien.cx/2025/10/27/%f0%9f%95%92-automating-periodic-tasks-with-eventbridge-scheduler-net-and-cloudformation-2/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.
