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