4.3.1. Synchronous and Asynchronous Invocation
💡 First Principle: Choose synchronous Bedrock invocation when the user or system needs the complete response before proceeding; choose asynchronous when the caller can continue working while the FM processes, and results can be delivered via notification or polling.
Synchronous invocation — Bedrock Converse API (recommended for new code):
import boto3, json
bedrock_runtime = boto3.client('bedrock-runtime', region_name='us-east-1')
# Converse API — consistent across all Bedrock models
response = bedrock_runtime.converse(
modelId='anthropic.claude-3-sonnet-20240229-v1:0',
system=[{'text': 'You are a helpful assistant.'}],
messages=[{'role': 'user', 'content': [{'text': user_query}]}],
inferenceConfig={'maxTokens': 1024, 'temperature': 0.3}
)
answer = response['output']['message']['content'][0]['text']
input_tokens = response['usage']['inputTokens']
output_tokens = response['usage']['outputTokens']
Asynchronous invocation via SQS — for background processing:
Asynchronous invocation with language-specific SDKs and SQS:
# Producer: enqueue job and return immediately
def submit_analysis_job(document_text: str) -> str:
job_id = str(uuid.uuid4())
sqs.send_message(
QueueUrl=ANALYSIS_QUEUE_URL,
MessageBody=json.dumps({'job_id': job_id, 'document': document_text}),
MessageAttributes={'priority': {'StringValue': 'normal', 'DataType': 'String'}}
)
# Store job in DynamoDB with 'pending' status
store_job_status(job_id, 'pending')
return job_id # Return immediately to caller
# Consumer Lambda: processes queue messages
def lambda_handler(event, context):
for record in event['Records']:
job = json.loads(record['body'])
update_job_status(job['job_id'], 'processing')
result = invoke_bedrock_analysis(job['document'])
store_job_result(job['job_id'], result)
update_job_status(job['job_id'], 'complete')
⚠️ Exam Trap: SQS standard queues deliver messages at least once, not exactly once. Your Lambda consumer must be idempotent — if the same job_id is processed twice (due to SQS redelivery), the second processing run should be a no-op. Check if the job is already in 'complete' status before invoking Bedrock.
Reflection Question: An application must process 10,000 legal documents overnight for summarization and classification. Processing one document takes an average of 8 seconds in Bedrock. What's the minimum time to process all documents synchronously in sequence? Design an async architecture that completes the batch in under 60 minutes.