8.0 KiB
Экземпляры и жизненный цикл
Способ управления экземплярами в точке входа скрипта определяет создание экземпляров Lua, вызовы Hook, сохранение состояния и уничтожение экземпляров. На этой странице правила описаны по типам жизненного цикла.
Жизненный цикл пула
Сейчас HandleRoute в скриптах маршрутизации и HandleDNSQuery в скриптах DNS используют экземпляры из пула. Следующие правила применяются к обоим Hook.
Пулы экземпляров и инициализация
Скрипты маршрутизации и DNS подключаются через поле script в соответствующих настройках и управляют отдельными пулами экземпляров Lua. Даже если указан один и тот же файл, состояние внутри экземпляров Lua не разделяется.
При запуске Xray один раз читает и компилирует скрипт, затем создаёт первый экземпляр, выполняет код верхнего уровня и проверяет наличие обязательного обработчика. Ошибка чтения файла, синтаксиса, выполнения кода верхнего уровня или проверки обработчика препятствует запуску Xray.
Вызовы Hook и возврат экземпляров
Каждый выбор маршрута или DNS-запрос получает экземпляр в исключительное пользование. Свободный экземпляр используется повторно; если параллельным вызовам нужны дополнительные экземпляры, они создаются из скомпилированного скрипта с повторным выполнением кода верхнего уровня.
После нормального завершения обработчика экземпляр может вернуться в пул для повторного использования. Необработанное исключение Lua или превышение времени выполнения уничтожает экземпляр. Сообщение об ошибке обработки через возвращаемые значения или ошибка их проверки не равнозначны исключению выполнения Lua: экземпляр можно использовать повторно. Лишние свободные экземпляры уничтожаются автоматически.
Если есть свободный экземпляр, путь вызова каждого Hook прост: получить экземпляр → выполнить Hook → вернуть экземпляр. Чтение и компиляция скрипта выполняются при запуске Xray. Зелёные узлы на схеме показывают этот обычный путь.
flowchart TD
LOAD["Запуск Xray<br/>Однократное чтение и компиляция основного скрипта"] --> INIT["Создать первый экземпляр Lua<br/>Выполнить код верхнего уровня и проверить Hook"]
INIT --> POOL[("Пул свободных экземпляров")]
subgraph CALL["Вызов Hook из пула: простой путь повторного использования"]
TAKE["Получить свободный экземпляр в исключительное пользование"] --> RUN["Выполнить HandleRoute / HandleDNSQuery"]
RUN -->|Нормальное завершение| PUT["Вернуть экземпляр, сохранив состояние"]
end
REQUEST["Выбор маршрута / DNS-запрос"] --> AVAILABLE{"Есть свободный экземпляр?"}
POOL -.-> AVAILABLE
AVAILABLE -->|Да| TAKE
PUT --> POOL
AVAILABLE -. Нет: расширить по необходимости .-> CREATE["Создать экземпляр из скомпилированного скрипта<br/>Выполнить код верхнего уровня и проверить Hook"]
CREATE --> RUN
RUN -. Необработанное исключение Lua / тайм-аут .-> DESTROY["Уничтожить экземпляр"]
POOL -. Лишние свободные экземпляры / завершение Xray .-> DESTROY
classDef reuse fill:#e8f5e9,stroke:#2e7d32,color:#1b5e20
class TAKE,RUN,PUT reuse
Состояние в экземплярах пула
Глобальные переменные, переменные local верхнего уровня, замыкания и кеш модулей require принадлежат текущему экземпляру. Они сохраняются между вызовами, которые он обрабатывает, и теряются при его уничтожении:
local calls = 0
function HandleRoute()
calls = calls + 1
return "direct", "instance-call-" .. calls
end
Счётчик выше отражает только число вызовов, обработанных текущим экземпляром. У разных экземпляров независимые значения calls, и запросы не обязательно попадают в один экземпляр. Этот счётчик нельзя использовать как общий для всех соединений или как постоянное состояние отдельного соединения.
Рекомендуется размещать код инициализации, например загрузку модулей Lua, создание объектов сопоставления и сохранение объектов DNS-серверов, вне функции Hook, на верхнем уровне скрипта. Он выполняется один раз при создании каждого экземпляра, а результаты могут повторно использоваться его последующими вызовами Hook.
Тайм-ауты и обновление скриптов
Сейчас тайм-аут инициализации каждого экземпляра маршрутизации и DNS составляет 120 секунд, а выполнения каждого вызова обработчика — 6 секунд. Тайм-аут вызова отсчитывается после получения экземпляра; отдельных полей конфигурации для этих значений пока нет. При вызовах API Xray фактическая отмена также зависит от того, реагирует ли API на сигнал отмены; отдельный DNS-сервер дополнительно ограничен настройкой timeoutMs.
Xray не отслеживает и не перекомпилирует основной скрипт автоматически. После его изменения перезапустите Xray, чтобы изменения вступили в силу. Экземпляры, созданные позже, также используют основной скрипт, скомпилированный при текущем запуске.