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

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

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

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

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

Код

export async function handler(event: any, context: any): Promise<object> {

console.log('event', event);
console.log('context', context);
return {
name: event.name
};
}

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

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

Функция

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

Сперва нам нужно скомпилировать функцию в JavaScript. Для этого мы можем использлвать null_resource и local-exec провиженер.

resource "null_resource" "build_typescript" {
provisioner "local-exec" {
command = "cd ../function && npm i && npm run build"
}
triggers = {
always_run = timestamp()
}
}

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

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

data "archive_file" "function_files" {
output_path = "./function.zip"
source_dir = "../dist"
type = "zip"
depends_on = [
null_resource.build_typescript
]
}

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

resource "yandex_function" "async_function" {
name = "async-function"
user_hash = data.archive_file.function_files.output_sha256
runtime = "nodejs18"
entrypoint = "main.handler"
memory = "128"
execution_timeout = "10"

content {
zip_filename = data.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
]
}

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

resource "yandex_function_iam_binding" "test_function_binding" {
function_id = yandex_function.async_function.id
# role = "serverless.functions.invoker"
role = "functions.functionInvoker"
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": "8b48ea46-998e8ab1-e74997d2-6c34a6ff",
"ReceiptHandle": "EAMgirSQrM0xKAI",
"MD5OfBody": "2b895b6efaa28b818284e5c696a18799",
"Body": "{\"name\":\"test\"}",
"Attributes": {
"ApproximateFirstReceiveTimestamp": "1704389253642",
"ApproximateReceiveCount": "1",
"SentTimestamp": "1704389248807",
"SenderId": "ajetd93tukrs738n9ib2@as"
}
}
]
}