Rüdiger Asche wrote at 06/20/2012 09:21 AM:
I have tried call-with-exception-handler and handlers in different variations but haven't been able to produce code that allows me to gracefully return to reestablishing the connection. Does anyone have a code snippet that helps me?

This is quick off-the-cuff suggestion to consider, not the only way to do this (nor any kind of canonical recipe for doing this sort of thing, nor necessarily the best way):

(let loop-connect ()
  (log-debug "Attempting connection..")
  (with-handlers ((exn:fail:network?
                   (lambda (exn)
                     (log-warning (string-append "network error: "
                                                 (exn-message exn)))
                     (let ((sleep-seconds (+ 3 (random 3))))
                       (log-debug
                        (format
                         "sleeping for ~A seconds before reconnect attempt"
                         sleep-seconds))
                       (sleep sleep-seconds)))))
   (let-values (((inport outport)
                 (tcp-connect somehostname somehostport)))
     (let loop-while-connected ()
       ....
       (read-something inport)
       ....
       (write-something outport)
       ...
       (loop-while-connected))))
  (loop-connect))

If you're hardcore: might want to also catch "exn:fail:network" within the "letrec-values", too, and try to close ports (perhaps in a different thread to close, or start a new thread for the new connection?) if not already closed, and then perhaps re-raise the exception so the handler above (within "loop-connect") attempts a new connection. As you know, but I'll mention it for the record: trying to close the ports might be a good idea, especially if your TCP stack is not great about timing them out, but if you have particular failure scenarios in an embedded system or similar, might help to test the scenarios and look at the IP traffic and how many times you fail to reconnect. You might also want to increase your retry delay on failures, in case you can flood the network or exhaust open ports on client or server. Say, each failure increments a counter by 2, and a successful read-write loop decrements the counter if greater than 1, then you use that number as the exponent in delay, or similar. (This complexity is not specific to Racket; the Racket-specific part is that you can catch a network error with "with-handlers".) BTW, if you have nothing else running on this processor, you might as well get in a GC cycle or two before sleeping. There are probably more details that could be covered if needed for this app, but one would have to work through it more closely.

Side comment on the internal-"define" controversy: I left the named-"let"s without arguments in this example, but one might find arguments to put in them by the time the program is finished and robust, such as for retry delay info, buffer management info, etc. Converting the named-"let"s to internal-"define", if the reader is so inclined, is left as an exercise for the reader. But perhaps internal-"define" people can see some of the appeal of named-"let" in this case.

Neil V.

____________________
 Racket Users list:
 http://lists.racket-lang.org/users

Reply via email to