Исключение переполнения стека в веб-проекте compojure - PullRequest
1 голос
/ 01 мая 2010

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

2010-04-20 15:33:20.963::WARN:  Error for /control
java.lang.StackOverflowError
    at clojure.lang.RT.seq(RT.java:440)
    at clojure.core$seq__4245.invoke(core.clj:105)
    at clojure.core$filter__5084$fn__5086.invoke(core.clj:1794)
    at clojure.lang.LazySeq.sval(LazySeq.java:42)
    at clojure.lang.LazySeq.seq(LazySeq.java:56)
    at clojure.lang.RT.seq(RT.java:440)
    at clojure.core$seq__4245.invoke(core.clj:105)
    at clojure.core$filter__5084$fn__5086.invoke(core.clj:1794)
    at clojure.lang.LazySeq.sval(LazySeq.java:42)
    at clojure.lang.LazySeq.seq(LazySeq.java:56)
    at clojure.lang.RT.seq(RT.java:440)
    at clojure.core$seq__4245.invoke(core.clj:105)
    at clojure.core$filter__5084$fn__5086.invoke(core.clj:1794)
    at clojure.lang.LazySeq.sval(LazySeq.java:42)
    at clojure.lang.LazySeq.seq(LazySeq.java:56)
    at clojure.lang.RT.seq(RT.java:440)
    at clojure.core$seq__4245.invoke(core.clj:105)
    at clojure.core$filter__5084$fn__5086.invoke(core.clj:1794)
    at clojure.lang.LazySeq.sval(LazySeq.java:42)
    at clojure.lang.LazySeq.seq(LazySeq.java:56)
    at clojure.lang.RT.seq(RT.java:440)
        ...

Если я делаю это сразу после этого, это всегда работает. Так что, похоже, это связано со временем или чем-то подобным. Код в вопросе:

(defn add-track [t]
  (common/ref-add tracks t))

(defn add-collection [coll]
  (doseq [track coll] (add-track track)))

и

(defn ref-add [ref value]
  (dosync (ref-set ref (conj @ref value))))

, где coll извлекается из этой функции:

(defn tracks-by-album [album]
  (sort sort-tracks (filter #(= (:album %) album) @tracks)))

, который использует:

(defn get-album-from-track [track]
  (seq/find-first #(= (:album track) (:name %)) @albums))

(defn sort-tracks [track1 track2]
  (cond (= (:album track1) (:album track2))
    (cond (and (:album-track track1) (:album-track track2))
      (< (:album-track track1) (:album-track track2))
      :else 0)
    :else
     (> (:year (get-album-from-track track1)) (:year (get-album-from-track track2)))))

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

(when-handle-command cmd params (audio/tracks-by-album decoded-name))

(defn when-handle-command [cmd params data]
  (println (str "handling command:" cmd))
    ....)

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

, так что, похоже, это функция треков за альбомом из стековой трассировки. Я просто не понимаю, почему это иногда работает, а иногда нет. Я говорю, что это треки за альбомом, потому что это единственная функция (включая детей), которая фильтрует, как видно из следа.

Весь исходный код доступен по адресу: http://code.google.com/p/mucomp/. Это мой маленький хобби-проект по изучению clojure, и пока он довольно глючный (это всего лишь одна ошибка :)), так что мне не очень понравилось говорить об этом. много об этом пока людей:)

1 Ответ

1 голос
/ 03 мая 2010

Я задал вопрос в списке рассылки clojure. И кажется, что ответ заключается в том, что фильтр возвращает ленивый seq, и когда вы их объедините, в какой-то момент вы закончите переполнением стека. Можно форсировать генерацию последовательности, используя doall.

...