AWS Lambda
Last updated
This example runs the Microsoft Entra ID and Microsoft licenses scripts as two scheduled AWS Lambda functions. Each invocation runs one complete batch.
For SDK requirements and environment variables, see Shared Setup.
Project Layout
Put the two example scripts next to a handler module, a requirements file, and an AWS SAM template:
.
├── aws_lambda.py
├── entra_employees.py
├── microsoft_licenses.py
├── requirements.txt
└── template.yaml
requirements.txt:
viio-sync-api-sdk>=0.5.0
The scripts use only the Python standard library and the SDK.
Lambda Handlers
Create aws_lambda.py:
import asyncio
from typing import Any
import entra_employees
import microsoft_licenses
def employees_handler(event: dict[str, Any], context: object) -> dict[str, Any]:
del event, context
counts = asyncio.run(entra_employees.run_batch(entra_employees.sync_employees))
return {"ok": True, **counts}
def licenses_handler(event: dict[str, Any], context: object) -> dict[str, Any]:
del event, context
counts = asyncio.run(microsoft_licenses.run_batch(microsoft_licenses.sync_microsoft_licenses))
return {"ok": True, **counts}
asyncio.run creates the Sync API client and closes it inside the invocation's event loop. This prevents a reused Lambda execution environment from keeping a gRPC AsyncIO channel bound to an earlier event loop.
If a sync fails, run_batch aborts the batch and the handler raises the error, so the invocation is reported as failed.
Schedule with AWS SAM
Create template.yaml. It deploys both functions with Python 3.11 on Arm64 and a 15-minute timeout. Amazon EventBridge Scheduler runs the employee sync at 02:00 UTC and the license sync at 03:00 UTC, so the two batches don't overlap:
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: Nightly Microsoft Graph syncs to the Viio Sync API
Parameters:
MicrosoftTenantId:
Type: String
MicrosoftClientId:
Type: String
MicrosoftClientSecret:
Type: String
NoEcho: true
ViioSyncApiEndpoint:
Type: String
Default: https://sync.viio.io
ViioSyncApiKey:
Type: String
NoEcho: true
ViioDirectIntegrationInstallationId:
Type: String
Globals:
Function:
Architectures:
- arm64
CodeUri: .
Runtime: python3.11
MemorySize: 512
Timeout: 900
Environment:
Variables:
MICROSOFT_TENANT_ID: !Ref MicrosoftTenantId
MICROSOFT_CLIENT_ID: !Ref MicrosoftClientId
MICROSOFT_CLIENT_SECRET: !Ref MicrosoftClientSecret
VIIO_SYNC_API_ENDPOINT: !Ref ViioSyncApiEndpoint
VIIO_SYNC_API_KEY: !Ref ViioSyncApiKey
VIIO_DIRECT_INTEGRATION_INSTALLATION_ID: !Ref ViioDirectIntegrationInstallationId
Resources:
EmployeeSyncFunction:
Type: AWS::Serverless::Function
Properties:
Handler: aws_lambda.employees_handler
Events:
NightlyEmployeeSync:
Type: ScheduleV2
Properties:
ScheduleExpression: cron(0 2 * * ? *)
ScheduleExpressionTimezone: UTC
LicenseSyncFunction:
Type: AWS::Serverless::Function
Properties:
Handler: aws_lambda.licenses_handler
Events:
NightlyLicenseSync:
Type: ScheduleV2
Properties:
ScheduleExpression: cron(0 3 * * ? *)
ScheduleExpressionTimezone: UTC
Lambda stops a function after 15 minutes. If a sync can take longer for your tenant, run the script on a scheduler without that limit, such as a container task.
Package Native Dependencies
grpcio contains native code. When building an Arm64 Lambda ZIP or layer on another operating system, install the matching Linux wheel:
python -m pip install \
--platform manylinux2014_aarch64 \
--implementation cp \
--python-version 3.11 \
--only-binary=:all: \
--target package \
"viio-sync-api-sdk>=0.5.0"
Replace 3.11 with the target Lambda runtime version. For an x86-64 function, use manylinux2014_x86_64. Python Lambda container images can install the package normally.