-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
Description
Overview
Implement a background job that automatically pauses coaching sessions after a period of inactivity. This prevents abandoned sessions from blocking other users and ensures clean session lifecycle management.
Background
The coaching session infrastructure already supports:
inactivity_timeout_minutesconfiguration per topic (default: 30 minutes)- Session status transitions including
active→paused updated_attimestamp tracking on each session
What's missing is the scheduled job that checks for and auto-pauses inactive sessions.
Requirements
1. Scheduled Job Implementation
Create a Lambda function or background task that:
- Runs on a schedule (every 5 minutes recommended)
- Queries for all
activesessions where:NOW() - updated_at > inactivity_timeout_minutes - Transitions matching sessions to
pausedstatus - Logs the auto-pause action for observability
2. Query Strategy
Option A: DynamoDB Scan with Filter (Simple but less efficient)
# Scan all active sessions, filter by updated_at
response = table.scan(
FilterExpression="session_status = :active AND updated_at < :threshold",
ExpressionAttributeValues={
":active": "active",
":threshold": (datetime.now(UTC) - timedelta(minutes=30)).isoformat()
}
)Option B: GSI on status + updated_at (More efficient, requires GSI)
- Create GSI:
status-updated_at-index - PK:
session_status - SK:
updated_at - Query active sessions with
updated_at < threshold
3. Auto-Pause Logic
async def auto_pause_inactive_sessions() -> int:
"""Auto-pause sessions inactive beyond their timeout threshold.
Returns:
Number of sessions auto-paused
"""
from coaching.src.core.coaching_topic_registry import COACHING_TOPIC_REGISTRY
paused_count = 0
# Get all active sessions
active_sessions = await repository.get_active_sessions()
for session in active_sessions:
# Get topic-specific timeout (default 30 min)
topic = COACHING_TOPIC_REGISTRY.get(session.topic_id)
timeout_minutes = topic.inactivity_timeout_minutes if topic else 30
# Check if session exceeds timeout
threshold = datetime.now(UTC) - timedelta(minutes=timeout_minutes)
if session.updated_at < threshold:
session.pause()
await repository.update(session)
logger.info(
"session.auto_paused",
session_id=session.session_id,
topic_id=session.topic_id,
inactive_minutes=(datetime.now(UTC) - session.updated_at).total_seconds() / 60
)
paused_count += 1
return paused_count4. Lambda Handler (if using AWS Lambda)
# coaching/src/lambdas/auto_pause_sessions.py
import structlog
from coaching.src.services.coaching_session_service import CoachingSessionService
logger = structlog.get_logger()
def handler(event, context):
"""Lambda handler for auto-pausing inactive sessions."""
service = CoachingSessionService(...)
try:
paused_count = service.auto_pause_inactive_sessions()
logger.info("auto_pause.completed", paused_count=paused_count)
return {
"statusCode": 200,
"body": {"paused_sessions": paused_count}
}
except Exception as e:
logger.error("auto_pause.failed", error=str(e))
raise5. Infrastructure (Pulumi)
# Add to coaching/pulumi/__main__.py
auto_pause_lambda = aws.lambda_.Function(
"auto-pause-sessions",
runtime="python3.11",
handler="coaching.src.lambdas.auto_pause_sessions.handler",
role=lambda_role.arn,
timeout=60,
memory_size=256,
environment={
"variables": {
"DYNAMODB_TABLE": sessions_table.name,
"ENVIRONMENT": environment,
}
}
)
# CloudWatch Events Rule - Run every 5 minutes
schedule_rule = aws.cloudwatch.EventRule(
"auto-pause-schedule",
schedule_expression="rate(5 minutes)",
)
aws.cloudwatch.EventTarget(
"auto-pause-target",
rule=schedule_rule.name,
arn=auto_pause_lambda.arn,
)
# Permission for CloudWatch to invoke Lambda
aws.lambda_.Permission(
"auto-pause-cloudwatch-permission",
action="lambda:InvokeFunction",
function=auto_pause_lambda.name,
principal="events.amazonaws.com",
source_arn=schedule_rule.arn,
)Files to Create/Modify
Create
coaching/src/lambdas/auto_pause_sessions.py- Lambda handlercoaching/tests/unit/lambdas/test_auto_pause_sessions.py- Unit tests
Modify
coaching/src/services/coaching_session_service.py- Addauto_pause_inactive_sessions()methodcoaching/src/infrastructure/repositories/dynamodb_coaching_session_repository.py- Addget_active_sessions()methodcoaching/pulumi/__main__.py- Add Lambda and CloudWatch infrastructure
Acceptance Criteria
-
auto_pause_inactive_sessions()method implemented in service - Repository method to query active sessions
- Lambda handler created
- Pulumi infrastructure for scheduled execution
- Unit tests for auto-pause logic
- Integration test verifying session state transition
- Structured logging for observability
- Sessions are paused based on topic-specific
inactivity_timeout_minutes
Testing
async def test_auto_pause_inactive_sessions():
"""Test that inactive sessions are auto-paused."""
# Create a session with old updated_at
session = create_test_session(
status="active",
updated_at=datetime.now(UTC) - timedelta(minutes=45) # 45 min ago
)
await repository.create(session)
# Run auto-pause
paused_count = await service.auto_pause_inactive_sessions()
# Verify
assert paused_count == 1
updated = await repository.get(session.session_id)
assert updated.status == "paused"Related
- Parent: Issue feat: Implement Generic Coaching Conversation Engine with Topic Registry #149 (Generic Coaching Engine)
- Config:
CoachingTopicDefinition.inactivity_timeout_minutes
Reactions are currently unavailable