Gopls: Запуск как демон

Примечание: эта функция новая. Если вы столкнётесь с ошибками, пожалуйста, сообщите о проблеме.

Если вы просто хотите попробовать это, перейдите к быстрому запуску.

Фон: Режимы выполнения gopls

Gopls изначально был реализован как LSP sidecar: процесс, запускаемый редакторами или их плагинами, и взаимодействующий с ним посредством jsonrpc 2.0 через stdin/stdout. Выполняясь как состоятельный процесс, gopls может сохранять значительный объём кэша и заранее выполнять анализ исходного кода, который редактируется.

Этот режим выполнения работает не так хорошо, когда имеется множество отдельных процессов редактора или когда процессы редактора имеют короткий срок жизни, как это часто бывает у пользователей редакторов без IDE, таких как Vim или Emacs. Наличие множества процессов означает наличие множества кэшей, что потребляет значительное количество системных ресурсов. Использование коротких сессий означает необходимость оплачивать затраты на запуск при каждом создании сессии.

Чтобы поддержать такие типы рабочих процессов, поддерживается новый режим выполнения gopls, при котором один постоянный общий процесс gopls "демон" отвечает за управление всеми сессиями gopls. В этом режиме редакторы по-прежнему запускают sidecar gopls, но этот sidecar служит лишь тонким "перенаправителем", ответственным за пересылку LSP к общему экземпляру gopls и запись метрик, журналов и трассировок rpc.

Быстрый запуск

Чтобы использовать общий экземпляр gopls, вы должны либо управлять процессом демона самостоятельно, либо позволить процессам-перенаправителям запускать общий демон по мере необходимости.

Запуск с флагом -remote=auto

Автоматическое управление демоном проще всего осуществить, передав флаг -remote=auto в процесс gopls, запущенный вашим редактором. Это приведёт к автоматическому запуску демона gopls при необходимости, подключению к нему и пересылке LSP. Например, вот разумная команда запуска gopls, которая устанавливает дополнительные флаги для более простого отладки:

<code class="language-bash">gopls -remote=auto -logfile=auto -debug=:0 -remote.debug=:0 -rpc.trace
</code>

Обратите внимание, что общий процесс gopls автоматически завершится через одну минуту без подключённых клиентов.

Ручное управление демоном

Чтобы управлять процессом демона gopls внешними средствами, а не позволять перенаправителям управлять им, вы должны запустить процесс демона gopls с флагом -listen=<addr>, а затем передать -remote=<addr> процессам gopls, запущенным вашим редактором.

Например, чтобы разместить демон на TCP-порту 37374, выполните:

<code class="language-bash">gopls -listen=:37374 -logfile=auto -debug=:0
</code>

А затем из редактора запустите

<code class="language-bash">gopls -remote=:37374 -logfile=auto -debug=:0 -rpc.trace
</code>

Если вы используете POSIX-совместимую систему, вы также можете использовать сокеты домена Unix, добавив префикс unix; к значениям флагов. Например:

<code class="language-bash">gopls -listen="unix;/tmp/gopls-daemon-socket" -logfile=auto -debug=:0
</code>

И подключаться с помощью:

<code class="language-bash">gopls -remote="unix;/tmp/gopls-daemon-socket" -logfile=auto -debug=:0 -rpc.trace
</code>

(Обратите внимание, что значения этих флагов ДОЛЖНЫ быть заключены в кавычки, поскольку «;» — это специальный символ оболочки. По этой причине синтаксис может быть изменён в будущем.)

Отладка

Отладка совместной сессии gopls сложнее, чем отладка одиночной сессии, поскольку теперь в работе LSP участвуют два процесса gopls. Ниже приведены некоторые советы:

Поиск файлов журналов и адресов отладки

При работе в режиме демона можно использовать команду gopls inspect sessions, чтобы найти файл журнала и порт отладки для экземпляра gopls демона (а также для всех подключённых клиентов). По умолчанию эта команда проверяет демон по умолчанию (то есть -remote=auto). Чтобы проверить другой демон, явно используйте флаг -remote: gopls -remote=localhost:12345 inspect sessions.

Это работает независимо от того, включён ли флаг -remote.debug.

Навигация по страницам отладки

Когда флаг -debug=:0 передаётся в gopls, запускается веб-сервер, который обслуживает динамические отладочные страницы (см. troubleshooting.md). Найти фактический порт, на котором размещены эти страницы, можно с помощью команды gopls inspect sessions или проверив начало файла журнала — это будет одно из первых сообщений. Например, если используется -logfile=auto, адрес отладки можно найти, проверив head /tmp/gopls-<pid>.log.

По умолчанию демон gopls запускается без флага -debug. Чтобы включить его, установите флаг -remote.debug в экземпляре пересылки, чтобы при запуске демона он вызывал gopls с флагом -debug.

Отладочные страницы процесса пересылки будут содержать ссылку на отладочные страницы серверного процесса демона. Соответственно, отладочные страницы демона будут содержать ссылки на каждого из его клиентов.

Это может помочь найти метрики, трассировки и файлы журналов для всех различных серверов и клиентов.

Использование файлов журналов

Демон gopls по умолчанию запускается без ведения журнала. Чтобы изменить это поведение, передайте флаг -remote.logfile в gopls пересылку. Используя -remote.logfile=auto, демон будет записывать журнал в расположение по умолчанию (в POSIX-системах: /tmp/gopls-daemon-<pid>.log).

Демон gopls не ведёт журнал сессионных сообщений: они вместо этого передаются обратно в пересылку, чтобы их можно было получить редактором. Журналы демона будут содержать только глобальные сообщения, например, журналы подключения и отключения сессий.

Рекомендуется запускать процесс forwarder gopls с ключом -rpc.trace, чтобы лог-файл содержал журналы трассировки RPC, специфичные для сеанса LSP.

Использование нескольких общих экземпляров gopls

В некоторых средах может возникнуть необходимость иметь более одного общего экземпляра gopls. Если управлять демоном вручную, это можно сделать, просто выбрав разные адреса -listen для каждого отдельного демон-процесса.

В POSIX-системах также поддерживается автоматическое управление различными общими процессами gopls: различные демоны могут быть выбраны путем передачи -remote="auto;<id>". Любые forwarder gopls, передающие одно и то же значение <id>, будут использовать один и тот же общий демон.

FAQ

Вопрос: Почему я не экономлю столько памяти, сколько ожидал, используя общий gopls?

Ответ: Как описано в implementation.md, gopls имеет концепцию представления/сеанса/кэша. Каждый сеанс и представление соответствуют ровно одному сеансу редактора (поскольку они содержат такие вещи, как отредактированные, но несохраненные буферы). Кэш содержит информацию, независимую от любого сеанса редактора, и поэтому может быть общим.

Когда, например, три сеанса редактора разделяют один процесс gopls, они будут делить кэш, но каждый будет иметь свой собственный сеанс и представление. Экономия памяти в этом режиме по сравнению с тремя отдельными процессами gopls соответствует объему пересечения кэша между сеансами.

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

Вопрос: Как настроить экземпляр демона при использовании -remote=auto?

Демон можно настроить с помощью флагов вида -remote.* в forwarder gopls. Это приводит к тому, что forwarder вызывает gopls с этими настройками при запуске демона. На момент написания, мы предоставляем следующую конфигурацию:

  • -remote.logfile: расположение лог-файла демона
  • -remote.debug: адрес отладки демона
  • -remote.listen.timeout: время, в течение которого демон должен ждать новые подключения, пока нет текущих подключений, прежде чем завершить работу. Должно быть установлено в корректное значение time.Duration (например, 30s или 5m). Если 0, ждать бесконечно. По умолчанию: 1m.

Обратите внимание, что после запуска демона установка этих флагов не изменит его конфигурацию. Эти флаги важны только для forwarder-процесса, который фактически запускает демон.


Исходные файлы для этой документации находятся в golang.org/x/tools/gopls/doc.

GoRu.dev Golang на русском

На сайте представлена адаптированная под русский язык документация языка программирования Golang