Перейти к основному содержимому

Асинхронный вызов

Функции в Yandex Cloud могут быть вызваны синхронно и асинхронно. Разница между ними заключается в том, что при синхронном вызове функция возвращает результат вызова, а при асинхронном - нет. В случае асинхронного вызова, клиент сразу получает ответ, что запрос принят, и функция выполняется в фоновом режиме.

Архитектура примера

архитектурная диаграмма Пользователь вызвав функцию, в ответ получает 202 Accepted, а функция выполняется в фоновом режиме. В случае успешного выполнения, функция отправляет сообщение в очередь сообщений success_queue, а в случае ошибки - в очередь failed_queue.

Код

package main

import (
"context"
"encoding/json"
"fmt"
)

type Req struct {
Name string `json:"name"`
}

func Handler(_ context.Context, req Req) ([]byte, error) {
// get body
fmt.Printf("Body: %+v\n", req)

// return response
resp := map[string]interface{}{
"result": "success",
"name": req.Name,
}

respBytes, err := json.Marshal(resp)
if err != nil {
panic(err)
}

return respBytes, nil

}

При чем как видно из кода, разработчику не нужно самому отправлять сообщение в очередь, это за него делает платформа.

Развертывание

Функция

Для развертывания этой функции в Yandex Cloud вы можете воспользоваться Terraform описанным в примере.

Для этого мы сначала определяем ресурс archive_file для создания zip-архива с функцией.

resource "archive_file" "function_files" {
output_path = "./function.zip"
source_dir = "../function"
type = "zip"
}

А затем ресурс yandex_function для создания функции в Yandex Cloud, куда передаем zip-архив с функцией.

resource "yandex_function" "async_function" {
name = "async-function"
user_hash = archive_file.function_files.output_sha256
runtime = "golang121"
entrypoint = "index.Handler"
memory = "128"
execution_timeout = "10"

content {
zip_filename = archive_file.function_files.output_path
}

async_invocation {
retries_count = "3"
service_account_id = yandex_iam_service_account.function_invoker.id
ymq_failure_target {
service_account_id = yandex_iam_service_account.ymq_writer.id
arn = yandex_message_queue.failed_queue.arn
}
ymq_success_target {
service_account_id = yandex_iam_service_account.ymq_writer.id
arn = yandex_message_queue.success_queue.arn
}
}

depends_on = [
yandex_resourcemanager_folder_iam_binding.function_invoker
]
}

Отдельно стоит обратить внимание на строки 13-24, где задаются параметры асинхронного вызова функции: количество попыток выполнения, сервисный аккаунт, который будет использоваться для выполнения функции, очереди YMQ.

И в конце, если мы хотим сделать функцию доступной из интернета, мы можем создать ресурс yandex_function_iam_binding что бы разрешить доступ к функции всем пользователям, тем самым сделав ее публичной.

resource "yandex_function_iam_binding" "test_function_binding" {
function_id = yandex_function.async_function.id
# role = "functions.functionInvoker"
role = "serverless.functions.invoker"
members = ["system:allUsers"]
}

Очереди сообщений

Для создания очередей сообщений в Yandex Message Queue, мы также воспользуемся Terraform.

resource "yandex_message_queue" "success_queue" {
name = "success_queue"
visibility_timeout_seconds = 600
receive_wait_time_seconds = 20
message_retention_seconds = 1209600
access_key = yandex_iam_service_account_static_access_key.sa_ymq_creator.access_key
secret_key = yandex_iam_service_account_static_access_key.sa_ymq_creator.secret_key
depends_on = [
yandex_iam_service_account_static_access_key.sa_ymq_creator,
yandex_iam_service_account.sa_ymq_creator,
yandex_resourcemanager_folder_iam_binding.sa_ymq_creator,
]
}

resource "yandex_message_queue" "failed_queue" {
name = "failed_queue"
visibility_timeout_seconds = 600
message_retention_seconds = 1209600
access_key = yandex_iam_service_account_static_access_key.sa_ymq_creator.access_key
secret_key = yandex_iam_service_account_static_access_key.sa_ymq_creator.secret_key
depends_on = [
yandex_iam_service_account_static_access_key.sa_ymq_creator,
yandex_iam_service_account.sa_ymq_creator,
yandex_resourcemanager_folder_iam_binding.sa_ymq_creator,
]
}

Запуск

Теперь, когда функция развернута, мы можем вызвать ее с помощью curl:

curl "https://functions.yandexcloud.net/$FUNCTION_ID?integration=async" \
-H "Content-Type: application/json" \
-d '{"name": "test"}' \
-X POST

Чтобы проверить ответ, нужно прочитать сообщения из очередей success_queue. Если вы разворачивали Terraform из примера, то можно воспользоваться командой:

QUEUE_URL=$(terraform output -raw ymq_id)
aws sqs receive-message --queue-url $QUEUE_URL --endpoint https://message-queue.api.cloud.yandex.net

Ответ должен быть примерно таким:

{
"Messages": [
{
"MessageId": "d387065-774b1206-85bf6f17-73b38758",
"ReceiptHandle": "EAEgw8PAq80xKAI",
"MD5OfBody": "e2b1c523c4703d2780f0f0a0fddbb905",
"Body": "{\"name\":\"test\",\"result\":\"success\"}",
"Attributes": {
"ApproximateFirstReceiveTimestamp": "1704387944899",
"ApproximateReceiveCount": "1",
"SentTimestamp": "1704387941053",
"SenderId": "aje2upl6d1anmqppsamg@as"
}
}
]
}