diff --git a/.github/workflows/go-function-offline-testing.yml b/.github/workflows/go-function-offline-testing.yml index a361efe..2d0b73f 100644 --- a/.github/workflows/go-function-offline-testing.yml +++ b/.github/workflows/go-function-offline-testing.yml @@ -14,7 +14,7 @@ jobs: matrix: tests: [ { directory: 'cors-go', go-version: '1.19' }, - { directory: 'go-hello-world', go-version: '1.20' } + { directory: 'go-hello-world', go-version: '1.20' }, { directory: 'go-mnq-sqs-publish', go-version: '1.18' }, { directory: 'go-upload-file-s3-multipart', go-version: '1.20' } ] diff --git a/functions/triggers-getting-started/.terraform.lock.hcl b/functions/triggers-getting-started/.terraform.lock.hcl index 2b742f4..ad00753 100644 --- a/functions/triggers-getting-started/.terraform.lock.hcl +++ b/functions/triggers-getting-started/.terraform.lock.hcl @@ -6,6 +6,7 @@ provider "registry.terraform.io/hashicorp/archive" { constraints = ">= 2.4.0" hashes = [ "h1:EtN1lnoHoov3rASpgGmh6zZ/W6aRCTgKC7iMwvFY1yc=", + "h1:ZtsrX5F13Ohsv/k/BvgyBVn0gF+lW4bkG7JmCGrN35Y=", "zh:18e408596dd53048f7fc8229098d0e3ad940b92036a24287eff63e2caec72594", "zh:392d4216ecd1a1fd933d23f4486b642a8480f934c13e2cae3c13b6b6a7e34a7b", "zh:655dd1fa5ca753a4ace21d0de3792d96fff429445717f2ce31c125d19c38f3ff", @@ -21,10 +22,30 @@ provider "registry.terraform.io/hashicorp/archive" { ] } +provider "registry.terraform.io/hashicorp/local" { + version = "2.4.1" + hashes = [ + "h1:V2G4qygMV0uHy+QTMlrjSyYgzpYmYyB6gWuE09+5CPI=", + "zh:244b445bf34ddbd167731cc6c6b95bbed231dc4493f8cc34bd6850cfe1f78528", + "zh:3c330bdb626123228a0d1b1daa6c741b4d5d484ab1c7ae5d2f48d4c9885cc5e9", + "zh:5ff5f9b791ddd7557e815449173f2db38d338e674d2d91800ac6e6d808de1d1d", + "zh:70206147104f4bf26ae67d730c995772f85bf23e28c2c2e7612c74f4dae3c46f", + "zh:75029676993accd6bef933c196b2fad51a9ec8a69a847dbbe96ec8ebf7926cdc", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:7d48d5999fe1fcdae9295a7c3448ac1541f5a24c474bd82df6d4fa3732483f2b", + "zh:b766b38b027f0f84028244d1c2f990431a37d4fc3ac645962924554016507e77", + "zh:bfc7ad301dada204cf51c59d8bd6a9a87de5fddb42190b4d6ba157d6e08a1f10", + "zh:c902b527702a8c5e2c25a6637d07bbb1690cb6c1e63917a5f6dc460efd18d43f", + "zh:d68ae0e1070cf429c46586bc87580c3ed113f76241da2b6e4f1a8348126b3c46", + "zh:f4903fd89f7c92a346ae9e666c2d0b6884c4474ae109e9b4bd15e7efaa4bfc29", + ] +} + provider "registry.terraform.io/scaleway/scaleway" { version = "2.31.0" constraints = ">= 2.31.0" hashes = [ + "h1:8kGZjp7iqVzDwNDxEw/9D4sYOZKC1ryrGkqFVUFPaNM=", "h1:jMenNvXtHG0vdQmNAQMmfat0K0KIjaO4l74puxFKr5g=", "zh:1519ac3651c441b32f80923c631835036d789b02fa3357ac7ad4fae3b459aad9", "zh:16054c16242c5f4384b3acb36428207060c8b265d03b6879daa745dd013af113", diff --git a/functions/triggers-getting-started/README.md b/functions/triggers-getting-started/README.md index 89ca090..2c05e1d 100644 --- a/functions/triggers-getting-started/README.md +++ b/functions/triggers-getting-started/README.md @@ -1,20 +1,22 @@ # Triggers Getting Started -Simple starter examples that showcase using SQS triggers in all Scaleway Functions supported languages. +Simple starter examples that showcase using SQS triggers or NATS triggers in all Scaleway Functions supported languages. -In each example, a function is triggered by a SQS queue with a message containing a number. The function will then print the factorial of this number to the logs. +In each example, a function is triggered by a SQS queue or a NATS subject with a message containing a number. +The function will then print the factorial of this number to the logs. ## Requirements This example requires [Terraform](https://www.scaleway.com/en/docs/tutorials/terraform-quickstart/). -Also, SQS **must** be [activated](https://www.scaleway.com/en/docs/serverless/messaging/how-to/get-started/#how-to-activate-sqs-or-sns) on your project. +Also,[SQS](https://www.scaleway.com/en/docs/serverless/messaging/how-to/get-started/#how-to-activate-sqs-or-sns) **must** be activated on your project, +and you **must** have a [NATS account](https://www.scaleway.com/en/docs/serverless/messaging/how-to/get-started/#how-to-create-a-nats-account). ## Setup The Terraform configuration will deploy a function for each language, showing how to use triggers with each language. -It will also create a SQS queue per function to trigger it. +It will also create a SQS queue per function and a NATS account to trigger it. After exporting `SCW_ACCESS_KEY`, `SCW_SECRET_KEY` and `SCW_DEFAULT_PROJECT_ID` variables (for authentication), you can: @@ -25,22 +27,31 @@ terraform apply You should be able to see your resources in the Scaleway console: -- Queues can be found in the [MnQ section](https://console.scaleway.com/messaging/protocols/fr-par/sqs/queues) +- Queues can be found in the Messaging section under [SQS](https://console.scaleway.com/messaging/protocols/fr-par/sqs/queues) +- NATS account can be found in the Messaging section under [NATS](https://console.scaleway.com/messaging/protocols/fr-par/nats/accounts) - Functions can be found in the `triggers-getting-started` namespace in the [Serverless functions section](https://console.scaleway.com/functions/namespaces) ## Running -You can trigger your functions by sending messages to any of the associated SQS queues. Below is a description of how to do this with our dummy `tests/send_messages.py` script. +You can trigger your functions by sending messages to any of the associated SQS queues or NATS subject. +Below is a description of how to do this with our dummy `tests/send_[sqs|nats]_messages.py` script. ### Setup -First you need to expose your SQS access and secret keys: +First, you need to expose your SQS access and secret keys: ```console export AWS_ACCESS_KEY_ID=$(terraform output -raw sqs_access_key) export AWS_SECRET_ACCESS_KEY=$(terraform output -raw sqs_secret_key) ``` +Or configure NATS credentials: + +```console +export NATS_CREDS_FILE=$(terraform output -raw creds_file) +export SUBJECT_NAME=$(terraform output -raw subject_name) +``` + Then you can set up a Python environment in the `tests` directory, e.g. ```console @@ -52,17 +63,24 @@ pip3 install -r requirements.txt ### Sending messages -Now you can run the `send_messages.py` script to send a message to the SQS queue of each function: +Now you can run the `send_sqs_messages.py` script to send a message to the SQS queue of each function: + +```console +python3 send_sqs_messages.py +``` + +Or you can run the `send_nats_messages.py` script to send a message to the NATS subject: ```console -python3 send_messages.py +python3 send_nats_messages.py ``` ### Viewing function logs -In your [Cockpit](https://console.scaleway.com/cockpit), you can access the logs from your queues and functions. +In your [Cockpit](https://console.scaleway.com/cockpit), you can access the logs from your queues, NATS account and functions. -Navigate from your Cockpit to Grafana, and find the `Serverless Functions Logs` dashboard. There you should see something like the following, showing that your functions were triggered by messages on the queues: +Navigate from your Cockpit to Grafana, and find the `Serverless Functions Logs` dashboard. +There you should see something like the following, showing that your functions were triggered by messages on the queues/NATS subject: ```console ... @@ -84,7 +102,9 @@ If you don't see these logs, make sure you have selected one of the "triggers ge ### Costs -Configuring and managing triggers is free, you only pay for the execution of your functions. For more information, please consult the [Scaleway Serverless pricing](https://www.scaleway.com/en/pricing/?tags=serverless). You will also be billed for the SQS queue usage when sending messages to it. +Configuring and managing triggers is free, you only pay for the execution of your functions. +For more information, please consult the [Scaleway Serverless pricing](https://www.scaleway.com/en/pricing/?tags=serverless). +You will also be billed for the SQS queue usage and NATS account when sending messages to it. ## Cleanup diff --git a/functions/triggers-getting-started/main.tf b/functions/triggers-getting-started/main.tf index 2eb222d..7b7e255 100644 --- a/functions/triggers-getting-started/main.tf +++ b/functions/triggers-getting-started/main.tf @@ -26,6 +26,7 @@ locals { handler = "handler" } } + subject_name = "triggers-nats-factorial" } resource "scaleway_function_namespace" "main" { @@ -59,21 +60,23 @@ resource "scaleway_function" "main" { min_scale = 0 } -resource "scaleway_mnq_sqs_queue" "main" { +resource "scaleway_function_trigger" "main_sqs" { for_each = local.functions - name = "factorial-requests-${each.key}" - - access_key = scaleway_mnq_sqs_credentials.main.access_key - secret_key = scaleway_mnq_sqs_credentials.main.secret_key + function_id = scaleway_function.main[each.key].id + name = "sqs-on-factorial-request" + sqs { + queue = scaleway_mnq_sqs_queue.main[each.key].name + } } -resource "scaleway_function_trigger" "main" { +resource "scaleway_function_trigger" "main_nats" { for_each = local.functions function_id = scaleway_function.main[each.key].id - name = "on-factorial-request" - sqs { - queue = scaleway_mnq_sqs_queue.main[each.key].name + name = "nats-on-factorial-request" + nats { + account_id = scaleway_mnq_nats_account.main.id + subject = local.subject_name } } diff --git a/functions/triggers-getting-started/messaging.tf b/functions/triggers-getting-started/messaging.tf deleted file mode 100644 index a6e5cef..0000000 --- a/functions/triggers-getting-started/messaging.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "scaleway_mnq_sqs_credentials" "main" { - name = "triggers-getting-started" - permissions { - can_publish = true - can_receive = true - can_manage = true - } -} diff --git a/functions/triggers-getting-started/nats.tf b/functions/triggers-getting-started/nats.tf new file mode 100644 index 0000000..dbfcc0a --- /dev/null +++ b/functions/triggers-getting-started/nats.tf @@ -0,0 +1,13 @@ +resource "scaleway_mnq_nats_account" "main" { + name = "nats-account" +} + +resource "scaleway_mnq_nats_credentials" "main" { + account_id = scaleway_mnq_nats_account.main.id + name = "triggers-nats" +} + +resource "local_sensitive_file" "nats" { + filename = "triggers-nats.creds" + content = scaleway_mnq_nats_credentials.main.file +} diff --git a/functions/triggers-getting-started/outputs.tf b/functions/triggers-getting-started/outputs.tf index c33b2c4..68f78eb 100644 --- a/functions/triggers-getting-started/outputs.tf +++ b/functions/triggers-getting-started/outputs.tf @@ -1,5 +1,5 @@ output "sqs_access_key" { - value = scaleway_mnq_sqs_credentials.main.access_key + value = scaleway_mnq_sqs_credentials.main.access_key sensitive = true } @@ -7,3 +7,11 @@ output "sqs_secret_key" { value = scaleway_mnq_sqs_credentials.main.secret_key sensitive = true } + +output "subject_name" { + value = local.subject_name +} + +output "creds_file" { + value = local_sensitive_file.nats.filename +} diff --git a/functions/triggers-getting-started/sqs.tf b/functions/triggers-getting-started/sqs.tf new file mode 100644 index 0000000..e5d74c2 --- /dev/null +++ b/functions/triggers-getting-started/sqs.tf @@ -0,0 +1,17 @@ +resource "scaleway_mnq_sqs_credentials" "main" { + name = "triggers-getting-started" + permissions { + can_publish = true + can_receive = true + can_manage = true + } +} + +resource "scaleway_mnq_sqs_queue" "main" { + for_each = local.functions + + name = "factorial-requests-${each.key}" + + access_key = scaleway_mnq_sqs_credentials.main.access_key + secret_key = scaleway_mnq_sqs_credentials.main.secret_key +} diff --git a/functions/triggers-getting-started/tests/requirements.txt b/functions/triggers-getting-started/tests/requirements.txt index ab48b6b..f2d577a 100644 --- a/functions/triggers-getting-started/tests/requirements.txt +++ b/functions/triggers-getting-started/tests/requirements.txt @@ -2,3 +2,5 @@ boto3<1.28.81 botocore<1.31.81 requests~=2.31.0 +nats-py==2.6.0 +nkeys==0.1.0 diff --git a/functions/triggers-getting-started/tests/send_nats_messages.py b/functions/triggers-getting-started/tests/send_nats_messages.py new file mode 100644 index 0000000..c2bc7a5 --- /dev/null +++ b/functions/triggers-getting-started/tests/send_nats_messages.py @@ -0,0 +1,24 @@ +import os + +import asyncio +import nats + +MAX_FACTORIAL_REQUESTS = 20 + +# Credentials file generated by Terraform +NATS_CREDS_FILE = os.environ["NATS_CREDS_FILE"] +NATS_ENDPOINT_URL = "nats://nats.mnq.fr-par.scaleway.com:4222" +SUBJECT_NAME = os.environ["NATS_SUBJECT"] + +async def send_nats(): + nc = await nats.connect(NATS_ENDPOINT_URL, user_credentials=NATS_CREDS_FILE) + + print(f"Sending 0..{MAX_FACTORIAL_REQUESTS} factorial requests to {SUBJECT_NAME}...") + for i in range(MAX_FACTORIAL_REQUESTS): + await nc.publish(SUBJECT_NAME, f"{i}".encode()) + + await nc.close() + + +if __name__ == "__main__": + asyncio.run(send_nats()) diff --git a/functions/triggers-getting-started/tests/send_messages.py b/functions/triggers-getting-started/tests/send_sqs_messages.py similarity index 100% rename from functions/triggers-getting-started/tests/send_messages.py rename to functions/triggers-getting-started/tests/send_sqs_messages.py