Асинхронный вызов
Функции в 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"
}
}
]
}