Непредсказуемое поведение с drakma-async и cl-async

Я пытаюсь использовать drakma-async в моем маленьком проекте. Но я просто не могу понять, что происходит. (Я использую emacs + slime + ccl). Мне нужно получить данные с http (s) и проанализировать их в обратном вызове. Я предполагаю, что могу получить неправильные данные, которые не могут быть проанализированы, поэтому я хочу повторить попытку. Но когда я пытался сделать несколько тестов, я просто не могу понять, что происходит...

(defun my-callback (data)
  (prin1 data)
  (restart-case
      (error "Some error parsing data...")
    (just-continue () (prin1 "Continue..."))))

(defun simple-test ()
  (let ((future (asf:make-future)))
    (as:delay #'(lambda () (asf:finish future "Some data")) :time 2)
    (prin1 (asf:future-finished-p future))
    (asf:attach future #'my-callback)))

(defun drakma-test ()
  (asf:alet ((response (das:http-request "http://www.google.com")))
    ;(prin1 (asf:future-finished-p response))
    (asf:attach response #'my-callback)))

(defun drakma-test-let ()
  (let ((response (das:http-request "http://www.google.com")))
    ;(prin1 (asf:future-finished-p response))
    (asf:attach response #'my-callback)))

(defun run-test (test)
  (as:start-event-loop test))

1) Итак, я сделаю то, что у меня есть на моем простом примере (это то, что я запланировал)

? (run-test #'simple-test)
NIL"Some data"    ;I get debugger here with simple-error and choose my restart
Invoking restart: #<RESTART JUST-CONTINUE #x7F0578EC20AD>
"Continue..."
1

2) Вот что я получаю во втором тесте:

? (run-test #'drakma-test)
"<A LOT OF HTML>
"
1

Где мой отладчик и мой перезапуск?

3) Раскомментируйте ;(prin1 (asf:future...)) линия в drakma-test

? (run-test #'drakma-test)
1

Нет законченного / незавершенного bool, No Data не распечатывается, я не получаю перезагрузку, я просто получаю 1 в результате.

4) Я предполагаю, что если я напишу (let ((reponse (das:http-request "http://www.google.com"))) ... )вместо (asf:alet ...) response не будет содержать future объект, но будет блокироваться, пока запрос не будет завершен и response будет содержать данные.

? (run-test #'drakma-test-let)
1

5) Раскомментируйте ;(prin1 (asf:future...)) линия в drakma-test-let

? (run-test #'drakma-test-let)
NIL   ;future is not finished
1

Данные не распечатываются, только то, что не закончено и результат run-test.

Я запустил тесты для cl-async, и все они прошли, кроме теста ipv6. Так что я просто не знаю, с чего начать понимать, что происходит... Почему я не получаю отладчик и перезагружаюсь во втором тесте? Почему ничего не происходит в 3-м тесте (это так же, как 2-й, но с prin1). Почему ничего не происходит в 5-м и 5-м тестах?

PS Не хватает репутации для создания drakma-async или же cl-async теги для этой библиотеки. я знаю это drakma-async построен над drakma поэтому я поставил этот тег.

1 ответ

Решение

Спасибо за комментарий mn, который прояснил ситуацию и кратко объяснил ситуацию.

Я сделал несколько примеров и хочу показать, что происходит в каждом случае:

Пример:

(defun my-callback (&rest data)
  (format t "Echo from callback: ~A~%" data)
  (restart-case
      (error "Some error parsing data...")
    (just-continue () (prin1 "Continue..."))))

(defun my-errback (e)
  (format t "Echo from errback: ~A~%" e))

(defun make-example-future ()
  (let ((future (asf:make-future))) ;creating future
    (as:delay #'(lambda ()          ;finishing future in 2 seconds
                  (asf:future-handler-case ;wrapping asf:finish
                    (asf:finish future
                                "Result data")
                    (t (e) (asf:signal-error future e)))) ;signal future an error
              :time 2)
    future))

(defun simple-test-2 ()
  (let ((future (make-example-future)))
    (format t "Is future?: ~A~%Finished?: ~A~%"  
            (asf:futurep future) (asf:future-finished-p future))
    (asf:alet ((result future))
      (asf:attach-errback future #'my-errback)
      (format t "Finished? ~A~%" (asf:future-finished-p future))
      (asf:future-finished-p result)
      (asf:attach result #'my-callback))))

И вот что происходит:

? (as:start-event-loop #'simple-test-2)
Is future?: T 
Finished?: NIL
;<here we have a 2 sec pause>
Finished? T
Echo from errback: There is no applicable method for the generic function:
#<STANDARD-GENERIC-FUNCTION CL-ASYNC-FUTURE:FUTURE-FINISHED-P #x302001B67A8F>
when called with arguments:
("Result data")

A) asf:alet дождитесь результата и привяжите значение результата к переменной. Так что я ошибался, думая, что asf:alet связать будущее.

Б) в make-example-future мы оборачиваем asf:finish с asf:future-handler-case и использовать asf:signal-error отправить ошибку в будущее. Это означает, что ошибка обрабатывается и errback будет называться. Даже если обратный вызов прикреплен позже в коде. Более того, ошибка с (asf:future-finished-p result) был обработан с future-handler-case потому что он был завернут в asf:alet (По крайней мере я так думаю).

C) Прокомментируйте (asf:future-finished-p result) и результат

Is future?: T
Finished?: NIL
Finished? T
Echo from callback: (Result data) ;here is my data
Echo from errback: Some error parsing data... ;;here is my error
1

В drakma-async есть подобное future-handler-case обертка, которая обертывает asf:finish,

Так что это объясняет #2 результат испытаний. Я получил данные и asf:alet вернул мне строку. Ошибка от обратного вызова была передана errbackкоторого у меня не было. Более того. В drakma-test используя только asf:alet Я просто не могу прикрепить errback потому что у меня нет доступа к будущему. Мне нужно позвонить http-request в let, не в alet,

Также это объясняет результат #3 тест: я получил ошибку в (future-finished-p) который был отправлен errback,

Если мы посмотрим на результат #4 а также #5 тест с новым my-callback: Видно, чтоcl-async попытаться вызвать мой обратный вызов со всеми значениями drakma вернулся. Есть 7 из них (значения, которые drakma:http-request вернуть). Поэтому я попытался ввести неправильное количество аргументов обратного вызова, и мои тесты № 4 и № 5 сигнализировали об ошибке, которая была просто обработана этим future-hander-case и отправить его errback,

Результат: в любом случае, кажется, что невозможно использовать перезагрузки с drakma-async не удаляя это future-handler-case потому что он отправляет ошибку в errback, но теряет все перезапуски.

Надеюсь, этот пост поможет, если кто-нибудь ответит на мой вопрос.

Другие вопросы по тегам