Схема, вызывающая сбой сборки uberimage

Я разрабатываю простое веб-приложение hello world на Clojure. Однако после того, как я добавил в свой проект библиотеку Schema, при попытке создать uberjar с использованием lein uberjar. Как ни странно, приложение по-прежнему проходит модульные тесты и работает без ошибок при запуске с lein dev.

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

Я уже пробовал отключить компиляцию AOT, так как это, кажется, основное различие между обычной компиляцией и сборкой uberjar, но без кубиков. Я также искал ключ «missing-required-key» в исходном коде схемы и убедился, что он правильно процитирован, это определенно похоже, поскольку, если я его изменю, тесты схемы начинают давать сбой.

(ns server.api
  (:require [aleph.http :as http]
            [compojure.api.sweet :refer :all]
            [compojure.route :as route]
            [com.stuartsierra.component :as component]
            [ring.middleware.reload :refer [wrap-reload]]
            [ring.util.http-response :refer :all]
            [schema.core :as s]
            [server.logging :refer [wrap-exception-logging wrap-request-logging] :as log]))

(s/defschema Greeting
  {:hello s/Str
   s/Keyword s/Any})

(defn app [db]
  (api
   {:format {:formats [:json-kw]}}
   (middlewares [wrap-request-logging
                 wrap-exception-logging]
                (swagger-ui "/docs" :swagger-docs "/endpoints")
                (swagger-docs "/endpoints"
                 {:info {:title "Hello World Api"}})

                (GET* "/greet" []
                      :summary "Greets someone by name."
                      :description "Greets a person by name, telling them about
                                    the database configuration we're using as well."
                      :return Greeting
                      :query-params [name :- s/Str]
                      (ok {:hello name :with-db db}))

                (route/not-found (not-found {:error "Page not found."})))))

(defrecord Api
  [port env db logger]
  component/Lifecycle

  (start [{:keys [connection] :as component}]
    (if connection
      component
      (do (log/info "Starting Api at port" port "with env" env)
          (let [application (app db)
                handler (if (= env :dev) (wrap-reload application) application)
                conn (http/start-server handler {:port port :join? false})]
            (assoc component :connection conn)))))

  (stop [{:keys [connection] :as component}]
    (if-not connection
      component
      (do (log/info "Stopping Api")
          (.close connection)
          (assoc component :connection nil)))))

(defn new-api [port env]
  (->Api port env nil nil))

Чем еще отличается процесс компиляции при создании uberjar от обычной компиляции? Есть еще что-нибудь, что я могу попробовать?

Основная причина в том, что для lein uberjar-маршрута задан недопустимый ввод (lein dev не указан, см. https://github.com/metosin/ring-swagger/blob/master/src/ring/swagger/swagger2_schema.clj#L13). Когда он добавлен, он работает как положено.


person CalumMcCall    schedule 19.06.2015    source источник


Ответы (4)


Тем не менее, данное исключение было действительно плохим, и теперь оно исправлено в последнем SNAPSHOT - использует значения по умолчанию для отсутствующих полей и, таким образом, не выполняет проверку схемы во время компиляции для него.

Кроме того, я бы рекомендовал не использовать AOT для всего приложения. См. https://github.com/metosin/compojure-api/issues/129

Я раньше не видел этой ошибки (и мы развертываем все наши службы со схемой и uberjar). Похоже, что строка 21 - это промежуточное ПО swagger-docs; Можете ли вы попробовать удалить это и посмотреть, решит ли это проблему?

person Tommi Reiman    schedule 23.06.2015

Я отреагировал на то, что вы используете _1_, предпочтительнее использовать _2_. Вероятно, это не ошибка, но это делает код намного проще для тех, кто не так много знает о библиотеках.

person Jason Wolfe    schedule 19.06.2015
comment
Чем больше я смотрю на _1_, тем меньше понимаю, как он оценивает свою таблицу маршрутов, и отладка этого должна быть кошмаром. Я бы действительно рекомендовал использовать другую, более явную библиотеку для облегчения Swagger. - person CalumMcCall; 22.06.2015

Я заглянул в compojure.api.sweet-namespace и увидел, что Potemkin используется Заком Теллмансом для «импорта» всех функций из различные пространства имен в ваше пространство имен service.api. Возможно, это создает проблемы при создании банки.

Не могли бы вы потребовать swagger-ui и swagger-docs из их исходного пространства имен, добавив эту строку к требованию?

Если это не сработает, но, по крайней мере, выдает другое сообщение об ошибке (возможно), попробуйте require все другие символы, используемые явно.

[compojure.api.swagger swagger-ui swagger-docs]

Не уверен, что это поможет, но попробуйте запустить :refer :all и посмотрите, каковы транзитивные зависимости. Может случиться так, что несколько библиотек зависят от разных несовместимых версий одной и той же зависимости. Я сталкивался с этим раньше, но я понятия не имею, почему это могло произойти только при упаковке в uberjar.

person claj    schedule 19.06.2015
comment
Спасибо за подробный ответ. Я пробовал ваши предложения, явно ссылаясь на все, но все равно получаю то же сообщение об ошибке. Возможно, проблема здесь в конфликте пространств имен между разными библиотеками, которые я использую? - person claj; 19.06.2015
comment
Я думаю, что в двух вложенных макросах есть конфликт. Может быть _1_ и посмотреть, компилируются ли полученные выражения ... - person CalumMcCall; 22.06.2015
comment
java.lang.RuntimeException: невозможно разрешить symbol: missing-required-key в этом контексте, компиляция: (server / api.clj: 21: 17) в clojure.lang.Compiler.analyze (Compiler.java:6464) в clojure .lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ VectorExpr.parse (Compiler.java:3126) в clojure.lang.Compiler.analyze (Compiler.java:6447) в clojure.lang. Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ MapExpr.parse (Compiler.java:2981) в clojure.lang.Compiler.analyze (Compiler.java:6453) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ MapExpr.parse (Compiler.java:2981) в clojure.lang.Compiler.analyze (Compiler.java:6453) в clojure.lang.Compiler.analyze (Compiler. java: 6406) на clojure.lang.Compiler $ InvokeExpr.parse (Compiler.java:3719) на clojure.lang.Compiler.analyzeSeq (Compiler.java:6646) на clojure.lang.Compiler.analyze (Compiler.java:6445 ) на clojure.lang.Comp iler.access $ 100 (Compiler.java:38) на clojure.lang.Compiler $ LetExpr $ Parser.parse (Compiler.java:6050) на clojure.lang.Compiler.analyzeSeq (Compiler.java:6644) на clojure.lang. Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6632) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyze (Compiler .java: 6406) в clojure.lang.Compiler $ InvokeExpr.parse (Compiler.java:3719) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6646) в clojure.lang.Compiler.analyze (Compiler.java: 6445) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ BodyExpr $ Parser.parse (Compiler.java:5782) в clojure.lang.Compiler $ LetExpr $ Parser.parse (компилятор .java: 6100) на clojure.lang.Compiler.analyzeSeq (Compiler.java:6644) на clojure.lang.Compiler.analyze (Compiler.java:6445) на clojure.lang.Compiler.analyzeSeq (Compiler.java:6632) на clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ BodyExpr $ Parser.parse (Compiler.java:5782) в clojure.lang.Compiler.analyzeSeq ( Compiler.java:6644) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ BodyExpr $ Parser.parse (Compiler .java: 5782) на clojure.lang.Compiler $ LetExpr $ Parser.parse (Compiler.java:6100) на clojure.lang. Compiler.analyzeSeq (Compiler.java:6644) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6632) в clojure.lang.Compiler.analyze (Компилятор .java: 6445) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ BodyExpr $ Parser.parse (Compiler.java:5782) в clojure.lang.Compiler $ LetExpr $ Parser. parse (Compiler.java:6100) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6644) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyzeSeq (Compiler.java : 6632) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6632) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure .lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ BodyExpr $ Parser.parse (Compiler.java:5782) в clojure.lang.Compiler $ LetExpr $ Parser.parse (Compiler.java:6100 ) на clojure.lang.Compiler .analyzeSeq (Compiler.java:6644) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6632) в clojure.lang.Compiler.analyze (Compiler. java: 6445) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6632) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ BodyExpr $ Parser.parse (Compiler.java:5782) в clojure.lang.Compiler $ FnMethod.parse (Compiler.java:5217) в clojure.lang.Compiler $ FnExpr.parse (Compiler.java: 3846) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6642) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6632) в clojure. lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ InvokeExpr.parse (Compiler.java:3719) в clojure.lang.Compiler .analyzeSeq (Compiler.java:66 46) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6632) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure. lang.Compiler.analyzeSeq (Compiler.java:6632) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ InvokeExpr .parse (Compiler.java:3719) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6646) в clojure.lang. Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6632) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyze (Compiler .java: 6406) в clojure.lang.Compiler $ InvokeExpr.parse (Compiler.java:3719) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6646) в clojure.lang.Compiler.analyze (Compiler.java: 6445) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ InvokeExpr.parse (Compiler.java:3719) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6646) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ InvokeExpr.parse (Compiler.java:3719) в clojure.lang .Compiler.analyzeSeq (Compiler.java:6646) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6632) в clojure.lang.Compiler.analyze ( Compiler.java:6 445) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6632) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure. lang.Compiler $ InvokeExpr.parse (Compiler.java:3719) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6646) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler .analyze (Compiler.java:6406) в clojure.lang.Compiler $ InvokeExpr.parse (Compiler.java:3719) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6646) в clojure.lang.Compiler.analyze ( Compiler.java:6445) на clojure.lang.Compiler.analyzeSeq (Compiler.java:6632) на clojure.lang.Compiler.analyze (Compiler.java:6445) на clojure.lang.Compiler.analyze (Compiler.java:6406 ) в clojure.lang.Compiler $ InvokeExpr.parse (Compiler.java:3719) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6646) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure .lang.Compi ler.analyzeSeq (Compiler.java:6632) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ BodyExpr $ Parser .parse (Compiler.java:5782) в clojure.lang.Compiler $ FnMethod.parse (Compiler.java:5217) в clojure.lang.Compiler $ FnExpr.parse (Compiler.java:3846) в clojure.lang.Compiler. analysisSeq (Compiler.java:6642) на clojure.lang.Compiler.analyze (Compiler.java:6445) на clojure.lang. Compiler.analyzeSeq (Compiler.java:6632) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.access $ 100 (Compiler.java:38) в clojure.lang.Compiler $ DefExpr $ Parser.parse (Compiler.java:538) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6644) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyze (Compiler .java: 6406) в clojure.lang.Compiler.compile1 (Compiler.java:7221) в clojure.lang.Compiler.compile (Compiler.java:7292) в clojure.lang.RT.compile (RT.java:398) в clojure.lang.RT.load (RT.java:438) в clojure.lang.RT.load (RT.java:411) в clojure.core $ load $ fn__5066.invoke (core.clj: 5641) в clojure. core $ load.doInvoke (core.clj: 5640) в clojure.lang.RestFn.invoke (RestFn.java:408) в clojure.core $ load_one.invoke (core.clj: 5446) в clojure.core $ compile $ fn__5071 .invoke (core.clj: 5652) в clojure.core $ compile.invoke (core.clj: 5651) у пользователя $ eval9 $ fn__16.invok e (form-init1857067608391167398.clj: 1) у пользователя $ eval9.invoke (form-init1857067608391167398.clj: 1) в clojure.lang.Compiler.eval (Compiler.java:6703) в clojure.lang.Compiler.eval (Компилятор .java: 6693) в clojure.lang.Compiler.load (Compiler.java:7130) в clojure.lang.Compiler.loadFile (Compiler.java:7086) в clojure.main $ load_script.invoke (main.clj: 274) в clojure.main $ init_opt.invoke (main.clj: 279) в clojure.main $ initialize.invoke (main.clj: 307) в clojure.main $ null_opt.invoke (main.clj: 342) в clojure.main $ main.doInvoke (main.clj: 420) в clojure.lang.RestFn.invoke (RestFn.java:421) в clojure.lang.Var.invoke (Var.java:383) в clojure.lang.AFn.applyToHelper (AFn .java: 156) в clojure.lang.Var.applyTo (Var.java:700) в clojure.main.main (main.java:37) Причина: java.lang.RuntimeException: невозможно разрешить символ: отсутствует-требуется -key в этом контексте в clojure.lang.Util.runtimeException (Util.java:221) в clojure.lang.Co mpiler.resolveIn (Compiler.java:6940) в clojure.lang.Compiler.resolve (Compiler.java:6884) в clojure.lang.Compiler.analyzeSymbol (Compiler.java:6845) в clojure.lang.Compiler.analyze (Компилятор .java: 6427) ... еще 153 Исключение в потоке «main» java.lang.RuntimeException: невозможно разрешить символ: отсутствует-требуемый-ключ в этом контексте, компиляция: (server / api.clj: 21: 17) в clojure.lang.Compiler.analyze (Compiler.java:6464) на clojure.lang.Compiler.analyze (Compiler.java:6406) на clojure.lang. Компилятор $ VectorExpr.parse (Compiler.java:3126) в clojure.lang.Compiler.analyze (Compiler.java:6447) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ MapExpr .parse (Compiler.java:2981) в clojure.lang.Compiler.analyze (Compiler.java:6453) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ MapExpr.parse ( Compiler.java:2981) в clojure.lang.Compiler.analyze (Compiler.java:6453) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ InvokeExpr.parse (Compiler.java : 3719) на clojure.lang.Compiler.analyzeSeq (Compiler.java:6646) на clojure.lang.Compiler.analyze (Compiler.java:6445) на clojure.lang.Compiler.access $ 100 (Compiler.java:38) в clojure.lang.Compiler $ LetExpr $ Parser.parse (Compiler.java:6050) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6644) в clojure.lang.Compiler.analyze (Compiler.java:6445) при закрытии .lang.Compiler.analyzeSeq ( Compiler.java:6632) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ InvokeExpr.parse (Compiler.java : 3719) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6646) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure .lang.Compiler $ BodyExpr $ Parser.parse (Compiler.java:5782) в clojure.lang.Compiler $ LetExpr $ Parser.parse (Compiler.java:6100) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6644 ) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6632) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang .Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ BodyExpr $ Parser.parse (Compiler.java:5782) в clojure.lang.Compiler.analyzeSeq (Compiler.java:6644) в clojure.lang. Compiler.analyze (Compiler.java:6 445) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler $ BodyExpr $ Parser.parse (Compiler.java:5782) в clojure.lang.Compiler $ LetExpr $ Parser.parse (компилятор .java: 6100) на clojure.lang.Compiler.analyzeSeq (Compiler.java:6632) на clojure.lang.Compiler.analyze (Compiler.java:6445) на clojure.lang.Compiler.access $ 100 (Compiler.java:38 ) в clojure.lang.Compiler $ DefExpr $ Parser.parse (Compiler.java:538) в clojure.lang. Compiler.analyzeSeq (Compiler.java:6644) в clojure.lang.Compiler.analyze (Compiler.java:6445) в clojure.lang.Compiler.analyze (Compiler.java:6406) в clojure.lang.Compiler.compile1 (Compiler .java: 7221) в clojure.lang.Compiler.compile (Compiler.java:7292) в clojure.lang.RT.compile (RT.java:398) в clojure.lang.RT.load (RT.java:438) в clojure.lang.RT.load (RT.java:411) в clojure.core $ load $ fn__5066.invoke (core.clj: 5641) в clojure.core $ load.doInvoke (core.clj: 5640) в clojure. lang.RestFn.invoke (RestFn.java:408) в clojure.core $ load_one.invoke (core.clj: 5446) в clojure.core $ compile $ fn__5071.invoke (core.clj: 5652) в clojure.core $ compile .invoke (core.clj: 5651) у пользователя $ eval9 $ fn__16.invoke (form-init1857067608391167398.clj: 1) у пользователя $ eval9.invoke (form-init1857067608391167398.clj: 1) в clojure.lang.Compiler.eval ( Compiler.java:6703) на clojure.lang.Compiler.eval (Compiler.java:6693) на clojure.lang.Compiler.load (Comp iler.java:7130) в clojure.lang.Compiler.loadFile (Compiler.java:7086) в clojure.main $ load_script.invoke (main.clj: 274) в clojure.main $ init_opt.invoke (main.clj: 279 ) в clojure.main $ initialize.invoke (main.clj: 307) в clojure.main $ null_opt.invoke (main.clj: 342) в clojure.main $ main.doInvoke (main.clj: 420) в clojure.lang .RestFn.invoke (RestFn.java:421) в clojure.lang.Var.invoke (Var.java:383) в clojure.lang.AFn.applyToHelper (AFn.java:156) в clojure.lang.Var.applyTo ( Var.java:700) в clojure.main.main (main.java:37) Вызвано: java.lang.RuntimeException: невозможно разрешить символ: отсутствует-требуемый-ключ в этом контексте в clojure.lang.Util.runtimeException ( Util.java:221) на clojure.lang.Compiler.resolveIn (Compiler.java:6940) на clojure.lang.Compiler.resolve (Compiler.java:6884) на clojure.lang.Compiler.analyzeSymbol (Compiler.java:6845 ) на clojure.lang.Compiler.analyze (Compiler.java:6427) ... еще 153 Компиляция f ailed: Ошибка подпроцесса - person claj; 22.06.2015

Спасибо за совет! Удаление строки 21/22 действительно решило проблему. Теперь мне нужно выяснить, почему чванство приводит к провалу ... Почему вы заподозрили, что проблема именно в этом?

person CraigM    schedule 22.06.2015