Перейти к содержанию

jsonrpc-batch: Модуль протокола JSONRPC batch для nginx-module-lua

Установка

Если вы еще не настроили подписку на репозиторий RPM, зарегистрируйтесь. Затем вы можете продолжить с следующими шагами.

CentOS/RHEL 7 или Amazon Linux 2

yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-jsonrpc-batch

CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023

dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-jsonrpc-batch

Чтобы использовать эту библиотеку Lua с NGINX, убедитесь, что nginx-module-lua установлен.

Этот документ описывает lua-resty-jsonrpc-batch v0.0.1, выпущенный 15 июля 2015 года.


Реализация Lua-Openresty JSON-RPC 2.0 Batch Request (http://www.jsonrpc.org/specification#batch).

Пакетный запрос является неблокирующим и выполняется параллельно, поскольку этот модуль использует location.capture_multi из ngx_lua. Таким образом, производительность высокая, а реализация проста.

Этот модуль разбирает пакетный запрос, проверяет его и выполняет несколько подзапросов к upstream-серверам. Обратите внимание, что у вас должен быть upstream JSON-RPC сервер по вашему выбору, но upstream-серверы не обязаны поддерживать пакетный запрос JSON-RPC.

Синопсис

Основное использование

server {
    location /api {
        # jsonrpc endpoint
    }
    location /api/batch {
        lua_need_request_body on;

        content_by_lua '
            local jsonrpc_batch = require "resty.jsonrpc.batch"
            client = jsonrpc_batch:new()
            local res, err = client:batch_request({
                path    = "/api",
                request = ngx.var.request_body,
            })
            if err then
                ngx.exit(500)
            end
            ngx.say(res)
        ';
    }
}

Расширенное использование

http {

    init_by_lua '
        local jsonrpc_batch = require "resty.jsonrpc.batch"
        client = jsonrpc_batch.new({
            -- ограничение на размер массива пакетного запроса
            max_batch_array_size = 10,
            -- для логирования времени ответа upstream
            before_subrequest = function(self, ctx, req)
                ctx.start_at = ngx.now()
            end,
            after_subrequest = function(self, ctx, resps, req)
                ngx.var.jsonrpc_upstream_response_time = ngx.now() - ctx.start_at
            end,
        })
    ';

    server {
        set $jsonrpc_upstream_response_time  -;

        location ~ /api/method/.* {
            # jsonrpc endpoint
        }

        location /api/batch {
            lua_need_request_body on;

            content_by_lua '
                local res, err = client:batch_request({
                    -- вы можете изменить конечную точку для каждого запроса
                    path = function(self, ctx, req)
                        return "/api/method/" .. req.method
                    end,
                    request  = ngx.var.request_body,
                });
                if err then
                    ngx.log(ngx.CRIT, err);
                    ngx.exit(500);
                end
                ngx.say(res);
            ';
        }
    }
}

Методы

new

usage:client = jsonrpc_batch:new(options)

Аргумент options — это таблица Lua, содержащая следующие ключи:

  • max_batch_array_size [Int]

Установите ограничение на размер json массива пакетного запроса. Когда приходит запрос, размер json массива которого превышает лимит, метод request возвращает недействительный json с ошибкой.

Значение по умолчанию — nil (без ограничения).

  • allow_single_request [Bool]

Этот модуль может принимать не только пакетные запросы, но и одиночные запросы (без пакетных запросов). Например, {"id":1, "jsonrpc": "2.0", "params": {}, "method": "hoge"} является одиночным запросом.

Если allow_single_request установлено в false, одиночный запрос приведет к недействительному json с ошибкой.

Значение по умолчанию — true.

  • before_subrequest [Function function(self, ctx)]

    Укажите функцию обратного вызова, которая срабатывает непосредственно перед выполнением подзапросов. Аргумент ctx — это объект Context.

    Например, вы можете установить переменную nginx (ngx.var) для логирования подзапросов, и вы можете динамически изменять параметры запроса.

  • after_subrequest [Function function(self, ctx)]

    Укажите функцию обратного вызова, которая срабатывает сразу после выполнения подзапросов. Аргумент ctx — это объект Context.

    Например, мы можем установить переменную nginx (ngx.var) для логирования результатов подзапросов, и мы можем динамически изменять ответы подзапросов.

request

usage:
res, err = client:request({
    path = "/api",
    request = ###jsonrpc request json###,
})

Декодирует json запроса и разделяет его, выполняя подзапросы параллельно к указанному path. Возвращает json ответа (res), который генерируется на основе всех ответов подзапросов. err содержит сообщение об ошибке, если в lua-скрипте произошла ошибка.

Он может принимать следующие параметры.

  • request [String] (обязательный)

    JSON запроса.

  • path [String или Function function(self, ctx, req)] (обязательный)

    Путь подзапроса, например "/api".

    Тип может быть функцией, которая динамически определяет путь для каждого подзапроса.

    Аргумент ctx — это объект Context.

    Аргумент req — это одиночный json запроса, включенный в массив json запросов пакетного запроса, например {"id":1, "jsonrpc": "2.0", "params": {"user_id": 1}, "method": "getUser"}.

    В качестве примера, мы можем использовать эту функцию для разделения конечных точек API по методу JSON-RPC и передавать информацию о первоначальном пути запроса в подзапрос.

    Следующий пример конфигурации показывает, что есть две конечные точки, и пакетные запросы распределяются по конечным точкам по методу jsonrpc. Кроме того, конечные точки имеют свою собственную версию API в качестве префикса пути.

    location ~ ^/(\d+\.\d+)/getUser$ {
        # jsonrpc endpoint 1
    }

    location ~ ^/(\d+\.\d+)/updateUser$ {
        # jsonrpc endpoint 2
    }

    location ~ ^/(\d+\.\d+)/batch$ {
        set $version $1;
        lua_need_request_body on;
        content_by_lua {
            local res, err = client:batch_request({
                path = function(self, ctx, req)
                    return "/" .. ngx.var.version  .. "/" .. req.method
                end,
                request = ngx.var.request_body,
            });
            if err then
              ngx.log(ngx.CRIT, err);
              ngx.exit(500);
              return;
            end
        };
    }
  • method (string) необязательный

    Укажите HTTP метод, используемый подзапросами. Значение по умолчанию — ngx.HTTP_POST.

Объект

Context

Функции обратного вызова before_subrequest, after_subrequest и path имеют объект Context в аргументах. Объект Context включает информацию о запросах и ответах подзапросов, поэтому значения, которые он имеет или не имеет, изменяются в зависимости от процесса запроса.

Объект Context — это таблица lua и имеет следующие ключи.

  • path [String или Function]

Указан методом request как path.

  • method [String]

Указан методом request как method.

  • raw_request [String]

json запроса, указанный методом request как request.

  • request [Table]

таблица lua, созданная путем декодирования json raw_request.

  • is_batch [Bool]

Является ли json запроса одиночным запросом или пакетным запросом.

  • subreq_reqs [Table]

Массив параметров подзапросов. Это аргументы ngx.location.capture_multi.

  • subreq_resps [Table]

Массив ответов подзапросов. Это ответ ngx.location.capture_multi.

GitHub

Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-jsonrpc-batch.