Lars Ingebrigtsen <la...@gnus.org> writes: > Eric Abrahamsen <e...@ericabrahamsen.net> writes: > >> On second thought you're not wrong here: the various *-open-server >> deffoos report their own failures with `nnheader-report' instead of >> signaling errors, and then `gnus-open-server' swallows any other errors >> and converts them to messages. > > Ah. I knew there was something like that somewhere. :-) > >> Failures arrived at via `gnus-request-scan' mostly show up as actual >> errors. > > Perhaps we should adjust those errors to be nnheader-report thingies > instead? > >> - When the gnus-open-server deffoo processes fail, they (or their >> downstream functions) signal 'gnus-server-connection-error. (I didn't >> go through and do this for every backend, just enough to get the >> idea.) >> - Mail source fetching can fail, in which case 'gnus-mail-source-error >> is signaled. nnmail.el no longer handles this error: it propagates up >> and out through gnus-request-scan. > > I've just skimmed the patch, but the approach looks sound to me (in > general). > >> Some observations and questions: >> >> - There are many places and depth-levels in Gnus where failure modes are >> dealt with as messages (in effect working like `with-demoted-errors') >> or as nil return values from functions, which are then converted into >> messages, or sometimes even re-signaled as an actual `error' with a >> new message string. This often ends up burying real errors, and/or >> making debug on error hard to use. We could try flattening this out: >> low-level functions signal errors, and only top-level functions in >> gnus-start/gnus-group/gnus-sum get to catch them at the last minute, >> and only if necessary (other layers can of course catch and re-signal >> the errors if some cleanup work needs to be done). I have no idea if >> this would end up working out, but I think it would be good to try. >> And more use of `condition-case-unless-debug' at the top level. > > I doubt it's possible to find an overarching strategy to handle all > kinds of errors on the "Gnus" level. Different errors are, well, > different.
Yeah, I'm trying to decide if it's worth introducing this new approach at all. I'd hate to put in something that ends up only being useful in 49% of cases, and now there's yet another system that future code readers have to make sense of. I'm also not sure it solves enough problems. For instance, I recently committed something to nnimap.el that cleans up `nnimap-process-buffers' when an IMAP connection dies. That happens in like three or four different places. Ideally a signal handling approach would let us do that cleanup in a single spot -- either an actual single spot, or a macro we only have to write once. Kind of a generalization of `nntp-with-open-group', except it catches any instance of 'gnus-server-error, rather than requiring an explicitly-thrown symbol. I don't quite see that this is feasible right now. ANYWAY... I sent a patch suggestion for the mail-source problem in a separate message. I'm kind of waffling on the rest of this custom error stuff. In the meantime I got a backtrace on my stop-the-world nntp connection error, which I've posted below. I guess there's nothing mysterious about it -- the process dies (I can't tell if it's actually the timeout doing it or not), and nntp-accept-process-output/nntp-report ends up raising the error, and there's nothing up the line to catch it. Does this look surprising or wrong for any reason? (if nntp--report-1 (progn (if nntp-record-commands (progn (nntp-record-command "*** CONNECTION LOST ***"))) (throw 'nntp-with-open-group-error t)) (if nntp-record-commands (progn (nntp-record-command "*** CALLED nntp-report ***"))) (nnheader-report 'nntp args) (debug) (apply #'error args)) nntp-report("Server closed connection") nntp-accept-process-output(#<process nntpd>) nntp-accept-response() #f(compiled-function () #<bytecode -0x16437790137177e>)() funcall(#f(compiled-function () #<bytecode -0x16437790137177e>)) (condition-case nil (funcall bodyfun) (quit (if debug-on-quit nil (nntp-close-server)) (signal 'quit nil))) (setq nntp-with-open-group-internal (condition-case nil (funcall bodyfun) (quit (if debug-on-quit nil (nntp-close-server)) (signal 'quit nil)))) (unwind-protect (setq nntp-with-open-group-internal (condition-case nil (funcall bodyfun) (quit (if debug-on-quit nil (nntp-close-server)) (signal 'quit nil)))) (if timer (progn (cancel-timer timer)))) (let ((timer (and nntp-connection-timeout (run-at-time nntp-connection-timeout nil #'(lambda nil (let* ... ...)))))) (unwind-protect (setq nntp-with-open-group-internal (condition-case nil (funcall bodyfun) (quit (if debug-on-quit nil (nntp-close-server)) (signal 'quit nil)))) (if timer (progn (cancel-timer timer)))) nil) (catch 'nntp-with-open-group-error (nntp-possibly-change-group group server connectionless) (let ((timer (and nntp-connection-timeout (run-at-time nntp-connection-timeout nil #'(lambda nil ...))))) (unwind-protect (setq nntp-with-open-group-internal (condition-case nil (funcall bodyfun) (quit (if debug-on-quit nil (nntp-close-server)) (signal 'quit nil)))) (if timer (progn (cancel-timer timer)))) nil)) (while (catch 'nntp-with-open-group-error (nntp-possibly-change-group group server connectionless) (let ((timer (and nntp-connection-timeout (run-at-time nntp-connection-timeout nil #'...)))) (unwind-protect (setq nntp-with-open-group-internal (condition-case nil (funcall bodyfun) (quit (if debug-on-quit nil ...) (signal ... nil)))) (if timer (progn (cancel-timer timer)))) nil)) (setq nntp--report-1 nntp-report-n)) (let ((nntp-report-n nntp--report-1) (nntp--report-1 t) (nntp-with-open-group-internal nil)) (while (catch 'nntp-with-open-group-error (nntp-possibly-change-group group server connectionless) (let ((timer (and nntp-connection-timeout (run-at-time nntp-connection-timeout nil ...)))) (unwind-protect (setq nntp-with-open-group-internal (condition-case nil (funcall bodyfun) (quit ... ...))) (if timer (progn (cancel-timer timer)))) nil)) (setq nntp--report-1 nntp-report-n)) nntp-with-open-group-internal) nntp-with-open-group-function(nil "news.gmane.io" nil #f(compiled-function () #<bytecode -0x16437790137177e>)) nntp-finish-retrieve-group-infos("news.gmane.io" ... 7) gnus-finish-retrieve-group-infos((nntp "news.gmane.io") ... 7) gnus-read-active-for-groups((nntp "news.gmane.io") ... 7)