Специальная переменная в hunchentoot

В настоящее время я разрабатываю 2 веб-инструмента для собственных нужд с помощью hunchentoot.
Перед запуском hunchentoot я хочу установить некоторую специальную переменную с помощью let, чтобы значения были доступны во время работы hunchentoot.

Нравится :

(let ((*db-path* "my-db-file"))
  (start-hunchentoot))

Но как только обработчикам выставляются счета, они больше не находятся в разрешении, и db-path возвращается к своему глобальному состоянию (которое равно nil).

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

Можно ли установить db-path таким образом, чтобы он был действителен для одного экземпляра hunchentoot, а не для другого?

Используемая среда — SBCL 1.2.4 на Debian Jessie.


person FireRain    schedule 22.10.2016    source источник
comment
Было бы лучше иметь класс для приложения со слотами для базы данных/другой конфигурации.   -  person jkiiski    schedule 22.10.2016
comment
Прямо сейчас я использую макрос with, но класс звучит более разумно.   -  person FireRain    schedule 22.10.2016


Ответы (1)


Вокруг метода

Добавление db-path в качестве слота в акцептор может быть подходящим вариантом. Однако вы также можете написать метод around для handle-request. Предполагая, что *my-acceptor* глобально привязано:

(defmethod hunchentoot:handle-request :around ((acceptor (eql *my-acceptor*)) request)
  (let ((*db-path* "my-db-file"))
    (call-next-method)))

Конечно, вам не нужно специализироваться на EQL, вместо этого вы можете определить свой собственный подкласс. Преимущество метода вокруг по сравнению с сохранением переменной конфигурации в экземпляре класса заключается в том, что вы сохраняете преимущества использования специальных переменных, т. е. привязки видны отовсюду в динамической области. Вот что говорится в строке документации, видимой на Lispdoc, о handle-request (выделено мной):

Эта функция вызывается после прочтения запроса и создания объекта REQUEST. Его работа состоит в том, чтобы фактически обрабатывать запрос, то есть возвращать что-то клиенту.

Может быть хорошим местом для методов вокруг, специализированных для вашего подкласса ACCEPTOR, которые связывают или перепривязывают специальные переменные, к которым затем могут обращаться ваши обработчики.

Я рекомендую вам прочитать документацию Hunchentoot.

Специальные переменные и потоки

Поведение, которое вы наблюдаете, связано с тем, что:

  • Сервер работает в другом потоке.
  • Динамические привязки являются локальными для каждого потока, как описано в руководстве:

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

    • global special values are visible across all threads;
    • привязки (например, с использованием LET) являются локальными для потока;
    • потоки не наследуют динамические привязки от родительского потока

Если вы создаете свои собственные потоки, вы можете создать замыкание, которое связывает переменные по своему усмотрению. Вы также можете использовать переносимую библиотеку bordeaux-threads, которая принимает список привязок к быть эффективным внутри потока.

person coredump    schedule 22.10.2016