AWS: Lambda, ECR, S3 and SNS

Deployment units

Unit Branch / build context Container command Trigger
KB router/indexer dev-woiceai-kb / woice_kb/ handler.lambda_handler SNS input topic
Website scraper dev-scrapper / scrapper/ handler.scrapper Synchronous invoke from KB Lambda
Optional provider chat dev-woiceai-chat / woice_chat/ handler.lambda_handler Direct API invoke, including key validation

Set SCRAPPER_LAMBDA_ARN to your scraper function ARN. If you enable provider chat, update the web service to invoke your compatibility Lambda. Configure each worker with its own ECR image tag.

The KB Dockerfile uses Lambda Python 3.9; the scraper uses an old Python 3.6 Lambda base and old Chromium/Chromedriver downloads. These are historical recipes, not a verified modern rebuild. Preserve a known working image digest if available. A rebuild may require a supported Lambda runtime, matching Chromium/driver, updated binary libraries and regression tests. Changing only the base version is insufficient.

ECR build/push procedure

Recommended shell outline; run from one service’s build context, with AWS CLI authenticated and the target account selected. Names below are chosen for a new installation, not verified live names.

export AWS_REGION=us-east-1
export AWS_ACCOUNT_ID=YOUR_ACCOUNT_ID
export ECR_REPOSITORY=woiceai-kb
export IMAGE_TAG=YOUR_RELEASE_TAG
export ECR_REGISTRY="$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com"
aws ecr create-repository --repository-name "$ECR_REPOSITORY" --region "$AWS_REGION"
aws ecr get-login-password --region "$AWS_REGION" | docker login --username AWS --password-stdin "$ECR_REGISTRY"
# Dockerfiles currently COPY .env. Supply an EMPTY .env, never a real credential file.
touch .env
docker buildx build --platform linux/amd64 --provenance=false --load -t "$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" .
docker push "$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"

Skip repository creation if it already exists. Build separate images for KB and scraper. Deploy x86_64 functions for these historical x86 browser binaries. Validate architecture rather than building an Apple Silicon default image. ECR and the Lambda function must be in the appropriate deployment region. Select the image URI/digest when creating a container-image Lambda, attach the execution role, then inject Python variables.

A Lambda function does not automatically redeploy when an existing ECR tag is pushed again. Update function code to the new image and wait for the update to complete. Prefer immutable release tags/digests:

aws lambda update-function-code --function-name YOUR_FUNCTION --image-uri YOUR_IMAGE_URI
aws lambda wait function-updated --function-name YOUR_FUNCTION

Record timeout, memory, ephemeral storage, architecture, concurrency, VPC/subnets, security groups, image digest and environment variable names. None are established by source alone. Choose limits from representative file/media and crawl tests. Lambda’s finite execution window constrains deep synchronous crawls and polling for cold GPU workers.

IAM and networking

Recommended permission boundaries:

Principal Needed access
Web API S3 Put/Get/Delete on its bucket prefix; SNS Publish to input topic; optional InvokeFunction on provider chat
KB Lambda S3 Get on originals; Publish update topic; InvokeFunction on scraper; CloudWatch logging
Scraper Lambda Publish update topic; logging; outbound HTTPS to crawled pages, RunPod, MongoDB Atlas
RunPod media workers S3 Get on originals and Publish update topic using dedicated AWS credentials; Atlas and RunPod access
SNS input topic Permission to invoke only KB Lambda
Deployment identity ECR push and controlled Lambda configuration/image updates

Atlas must allow the workers’ network access. Lambda VPC placement without internet/NAT can break RunPod, websites, Atlas DNS, or S3/public endpoints. Configure these dependencies deliberately. The existing AWS SDK clients may explicitly pass static keys; attaching a role alone does not guarantee that every code path uses it. See configuration caveats.

Input SNS topic

Create an input SNS topic and configure its ARN in the web app. Subscribe KB Lambda with protocol Lambda, and add its resource-based permission allowing sns.amazonaws.com with SourceArn restricted to that topic. The scraper is invoked by the KB function; it does not need a separate input-topic subscription for the main flow.

Input attributes are the routing contract: KNOWLEDGEBASE.ID, .CONTENT, .CONTENT_TYPE, .ACTION, optional .TEXT, .TITLE, .URL_DEPTH, .UNIQUE_ID, and worker-side optional .MONGODB_SRV_ID. Use native SNS delivery with its Records[0].Sns.MessageAttributes envelope. These handlers process only the first record in the inspected implementation.

Update SNS topic and HTTPS callback

Create an SNS topic for indexing updates. Configure worker publishers and subscribe https://YOUR_API_HOST/knowledgebase/webhook using HTTPS. The API also exposes /api/webhook/webhook, /api/webhook/sns and /knowledgebase/sns through its two router mounts. Use the first canonical path consistently.

The callback handles SubscriptionConfirmation by fetching SubscribeURL and handles Notification by reading MessageAttributes. Allow SNS’s text/plain JSON envelope through the proxy. Use standard SNS delivery, not raw message delivery, since the handler needs envelope attributes. Confirm that the subscription is no longer pending before testing indexing.

Required hardening for an untrusted public deployment: the inspected webhook accepts SNS-shaped traffic without verifying its signature/topic and fetches a submitted confirmation URL. Add SNS signature/certificate validation, expected-topic checks and safe AWS confirmation-URL validation before relying on this route publicly. This is a concrete property of the supplied handler, not an extra existing service.

Recommended operations: configure SNS delivery monitoring and a failure destination/DLQ where supported by the chosen subscription/Lambda setup. Capture both Lambda invocation errors and application-level Failed attributes: returning a Failed dictionary may still count as a successful Lambda invocation.

Optional provider Lambda

If the web offers non-Qwen models, build the compatibility service from its own branch, supply its DB_URI, RunPod embedding/rewrite configuration, and MongoDB keys records. It expects provider keys by api_key_id. Recover/test the SQL-to-Mongo key bridge before enabling this path. This does not replace the active chat-all-models RunPod deployment.