Непредсказуемое поведение с 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, но теряет все перезапуски.
Надеюсь, этот пост поможет, если кто-нибудь ответит на мой вопрос.