This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-performance-tests.git
commit 39041a1bcd4e1984966a9ae61b3f7c5df55809c2 Author: Claus Ibsen <[email protected]> AuthorDate: Mon Nov 2 12:25:19 2026 +0100 ai-benchmark: connect-aws-s3-sqs in the new set, S3 and SQS on the AWS emulator of camel infra run aws s3 camel infra run aws s3 starts Floci (mirror.gcr.io/floci/floci:2.4.0), an AWS emulator with S3, SQS and more in one container on localhost:4566. The project starts with a route that logs the order files of orders/. 1. Connect (endpoint override, region and keys in the request), upload each order file to the bucket orders with its file name as the key, and log it. Restart, as jms step 1: the log, and the bucket lists the object. 2. A route new-objects consumes the bucket, reads the order id from the object (a stream) into a variable, and sends the event {"orderId", "object"} to the SQS queue order-events. Restart: the log, and the queue holds the event, with both fields. 3. A route order-events consumes the queue and logs the event's fields. 4. Archive: the consumer moves each object to the bucket orders-archive (moveAfterRead): the archive bucket lists the objects. The probes read the bucket and the queue over the emulator's HTTP API, which answers requests without a signature: ListObjectsV2, and a ReceiveMessage with VisibilityTimeout 0, which leaves the messages on the queue. The checkpoint purges the queue when it resets a step (checkpoint_requests). Reference pass: 4 of 4, twice. Negative pass: 0 of 4. Model run (k=1, qwen3.6:35b-mlx, before the queue purge): steps 1 and 2 passed. Steps 3 and 4 had the right end state, but failed on errors: their consumer read messages that were not valid JSON (JsonParseException), left on the queue by the model's own first tries in step 2. The checkpoint purge is for that case. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_016Y4dDi5iQNgtHrDdz2NpwF --- ai-benchmark/gen_stepwise.py | 69 ++++++++++++++++++++++ .../seed/connect-aws-s3-sqs/orders/order-1001.json | 2 + .../seed/connect-aws-s3-sqs/orders/order-1002.json | 2 + .../seed/connect-aws-s3-sqs/orders/order-1003.json | 2 + 4 files changed, 75 insertions(+) diff --git a/ai-benchmark/gen_stepwise.py b/ai-benchmark/gen_stepwise.py index 4aec1fe..9b9da6d 100644 --- a/ai-benchmark/gen_stepwise.py +++ b/ai-benchmark/gen_stepwise.py @@ -1189,6 +1189,75 @@ EXAMPLES.append({ ]}) +# ---------------------------------------------------------------- connect-aws-s3-sqs (S3 and SQS on the emulator of camel infra run aws) +# Claus, Nov 2: the order files go to an S3 bucket; a route takes each new object and sends an event with the order id +# to an SQS queue; another route consumes the queue; and the processed objects are archived. `camel infra run aws s3` +# starts Floci, an AWS emulator with S3, SQS and more in one container on http://localhost:4566. The probes read the +# bucket and the queue over its HTTP API, which answers requests without a signature: ListObjectsV2, and a +# ReceiveMessage with VisibilityTimeout 0, which leaves the messages on the queue. An S3 object arrives as a stream. +AS = "aws-orders.camel.yaml" +AS_PROPS = ("# The AWS services started by: camel infra run aws s3\n" + "camel.component.aws2-s3.access-key=accesskey\ncamel.component.aws2-s3.secret-key=secretkey\n" + "camel.component.aws2-s3.region=us-east-1\ncamel.component.aws2-s3.override-endpoint=true\n" + "camel.component.aws2-s3.uri-endpoint-override=http://localhost:4566\n") +AS_PROPS_SQS = AS_PROPS + AS_PROPS.split("\n", 1)[1].replace("aws2-s3", "aws2-sqs") +AS_UPLOAD = (" - to:\n uri: aws2-s3\n parameters:\n bucketNameOrArn: orders\n" + " autoCreateBucket: true\n keyName: \"${file:name}\"\n") +def as_new_objects(archive): + frm = " uri: aws2-s3\n parameters:\n bucketNameOrArn: orders\n" + ( + " moveAfterRead: true\n destinationBucket: orders-archive\n autoCreateBucket: true\n" if archive else "") + return route("new-objects", frm, + " - setVariable:\n name: orderId\n expression:\n jsonpath:\n" + " expression: \"$.orderId\"\n" + " - setBody:\n expression:\n simple:\n" + " expression: '{\"orderId\": \"${variable.orderId}\", \"object\": \"${header.CamelAwsS3Key}\"}'\n" + " - to:\n uri: aws2-sqs\n parameters:\n queueNameOrArn: order-events\n" + " autoCreateQueue: true\n" + + log("Event for ${variable.orderId} sent to the queue order-events")) +AS_EVENTS = route("order-events", " uri: aws2-sqs\n parameters:\n queueNameOrArn: order-events\n autoCreateQueue: true\n", + UNMARSHAL + log("Event received for ${body[orderId]} (object ${body[object]})")) +as_s0 = route("incoming-orders", FILE_ORDERS, log("Order file ${file:name} received")) +as_s1 = route("incoming-orders", FILE_ORDERS, AS_UPLOAD + log("Uploaded ${file:name} to the bucket orders")) +as_s2 = as_s1 + "\n" + as_new_objects(False) +as_s3 = as_s2 + "\n" + AS_EVENTS +as_s4 = as_s1 + "\n" + as_new_objects(True) + "\n" + AS_EVENTS +AWS = "http://localhost:4566" +S3_LIST = lambda bucket, key: {"method": "GET", "url": AWS + "/" + bucket + "?list-type=2", "expect_status": 200, + "body_regex": "<Key>" + key.replace(".", "\\.") + "</Key>"} +# the event as the queue holds it: the message body is a JSON string inside the JSON answer, its quotes escaped +SQS_PEEK = lambda rx: {"method": "POST", "url": AWS + "/", "expect_status": 200, "body_regex": rx, + "headers": {"Content-Type": "application/x-amz-json-1.0", "X-Amz-Target": "AmazonSQS.ReceiveMessage"}, + "body": json.dumps({"QueueUrl": AWS + "/000000000000/order-events", "MaxNumberOfMessages": 10, + "VisibilityTimeout": 0})} +# the checkpoint empties the queue: messages that a model's earlier try could not write as JSON would make the next +# step's consumer fail on them, again after every visibility timeout (awsm1, steps 3 and 4) +SQS_PURGE = {"method": "POST", "url": AWS + "/", "note": "(purge the queue order-events)", + "headers": {"Content-Type": "application/x-amz-json-1.0", "X-Amz-Target": "AmazonSQS.PurgeQueue"}, + "body": json.dumps({"QueueUrl": AWS + "/000000000000/order-events"})} +EXAMPLES.append({ + "name": "connect-aws-s3-sqs", "route_file": AS, "props_file": "application.properties", "wait_seconds": 15, + "seed": "connect-aws-s3-sqs", "infra": ["aws s3"], "checkpoint_requests": [SQS_PURGE], "steps_dir": NEW, + "initial": {AS: as_s0, "application.properties": "# application properties\n"}, + "steps": [ + {"request": "Connect to the AWS services that camel infra started: endpoint override http://localhost:4566, region us-east-1, access key accesskey, secret key secretkey. Upload each order file to the S3 bucket orders, with the file name as the object key, and create the bucket if it does not exist. Log \"Uploaded ${file:name} to the bucket orders\" instead of received. The integration is restarted after your change, so new connection settings apply.", + # a reload does not apply camel.component.* properties to a component that exists already: a first try + # without them would keep the component without its endpoint, so the step restarts, as jms step 1 does + "check": {"file_regex": "aws2-s3", "log_regex": ["Uploaded order-1001\\.json to the bucket orders", "Uploaded order-1003\\.json to the bucket orders"], + "probes": [S3_LIST("orders", "order-1001.json")]}, + "reference": {AS: as_s1, "application.properties": AS_PROPS}, "restart": True}, + {"request": "Add a route new-objects that consumes the new objects of the bucket orders; for now the consumer may delete each object after reading it. Read the order id from the JSON of the object into a variable orderId, send the event {\"orderId\": \"<order id>\", \"object\": \"<object key>\"} as JSON text to the SQS queue order-events (create the queue if it does not exist), and log \"Event for ${variable.orderId} sent to the queue order-events\". The integration is restarted [...] + "check": {"file_regex": "aws2-sqs", "log_regex": ["Event for ORD-1001 sent to the queue order-events", "Event for ORD-1003 sent to the queue order-events"], + "probes": [SQS_PEEK(r'\\"orderId\\":\s*\\"ORD-100[123]\\"'), SQS_PEEK(r'\\"object\\":\s*\\"order-100[123]\.json\\"')]}, + "reference": {AS: as_s2, "application.properties": AS_PROPS_SQS}, "restart": True}, + {"request": "Add a route order-events that consumes the queue order-events, unmarshals the event from JSON and logs \"Event received for ${body[orderId]} (object ${body[object]})\".", + "check": {"log_regex": ["Event received for ORD-1001 \\(object order-1001\\.json\\)", "Event received for ORD-1003 \\(object order-1003\\.json\\)"]}, + "reference": {AS: as_s3}}, + {"request": "Keep the processed orders: instead of only deleting each object of the bucket orders after it is read, move it to the bucket orders-archive, and create that bucket if it does not exist.", + "check": {"file_regex": "orders-archive", "probes": [S3_LIST("orders-archive", "order-1001.json"), S3_LIST("orders-archive", "order-1003.json")]}, + "reference": {AS: as_s4}}, + ]}) + + def write_project(ex): d = os.path.join(PROJECTS, ex["name"]) shutil.rmtree(d, ignore_errors=True) diff --git a/ai-benchmark/seed/connect-aws-s3-sqs/orders/order-1001.json b/ai-benchmark/seed/connect-aws-s3-sqs/orders/order-1001.json new file mode 100644 index 0000000..3eb5f03 --- /dev/null +++ b/ai-benchmark/seed/connect-aws-s3-sqs/orders/order-1001.json @@ -0,0 +1,2 @@ +{"orderId": "ORD-1001", "customer": "C-482", "country": "DK", "status": "paid", + "lines": [{"sku": "CAMEL-TSHIRT", "qty": 2, "price": 19.95}, {"sku": "CAMEL-MUG", "qty": 1, "price": 9.50}]} diff --git a/ai-benchmark/seed/connect-aws-s3-sqs/orders/order-1002.json b/ai-benchmark/seed/connect-aws-s3-sqs/orders/order-1002.json new file mode 100644 index 0000000..bb7aa0e --- /dev/null +++ b/ai-benchmark/seed/connect-aws-s3-sqs/orders/order-1002.json @@ -0,0 +1,2 @@ +{"orderId": "ORD-1002", "customer": "C-207", "country": "DE", "status": "paid", + "lines": [{"sku": "CAMEL-MUG", "qty": 3, "price": 9.50}]} diff --git a/ai-benchmark/seed/connect-aws-s3-sqs/orders/order-1003.json b/ai-benchmark/seed/connect-aws-s3-sqs/orders/order-1003.json new file mode 100644 index 0000000..9edab76 --- /dev/null +++ b/ai-benchmark/seed/connect-aws-s3-sqs/orders/order-1003.json @@ -0,0 +1,2 @@ +{"orderId": "ORD-1003", "customer": "C-134", "country": "US", "status": "pending", + "lines": [{"sku": "CAMEL-TSHIRT", "qty": 1, "price": 19.95}, {"sku": "CAMEL-CAP", "qty": 1, "price": 14.00}, {"sku": "CAMEL-MUG", "qty": 2, "price": 9.50}]}
