Sfoglia il codice sorgente

Retries with back-off

Innocenty Enikeew 10 anni fa
parent
commit
adff5ab2b6
3 ha cambiato i file con 55 aggiunte e 20 eliminazioni
  1. 10 13
      chatikbot.lisp
  2. 27 7
      telegram.lisp
  3. 18 0
      utils.lisp

+ 10 - 13
chatikbot.lisp

@@ -12,16 +12,13 @@
 (defvar *admins* nil "Admins chat-ids")
 
 (defun process-updates ()
-  (handler-case
-      (loop for update in (telegram-get-updates :offset (and *telegram-last-update*
-                                                             (1+ *telegram-last-update*))
-                                                :timeout 300)
-         do (setf *telegram-last-update*
-                  (max (or *telegram-last-update* 0)
-                       (aget "update_id" update)))
-         do (handle-message (aget "message" update)))
-    (error (e)
-      (log:error e))))
+  (loop for update in (telegram-get-updates :offset (and *telegram-last-update*
+                                                         (1+ *telegram-last-update*))
+                                            :timeout 300)
+     do (setf *telegram-last-update*
+              (max (or *telegram-last-update* 0)
+                   (aget "update_id" update)))
+     do (handle-message (aget "message" update))))
 
 (defvar *responses*
   '((:text . "И чё?")
@@ -222,8 +219,9 @@
                            :daily (find "daily" args :key #'string-downcase :test #'equal)))
          "Так а ты чьих будешь?"))))
 
+
 (defun start ()
-  (mapc #'sb-ext:unschedule-timer (trivial-timers:list-all-timers))
+  (mapc #'trivial-timers:unschedule-timer (trivial-timers:list-all-timers))
   (let ((old-updates (find "process-updates"
                             (bordeaux-threads:all-threads)
                             :key #'bordeaux-threads:thread-name
@@ -238,6 +236,5 @@
    :thread t)
   (bordeaux-threads:make-thread
    (lambda ()
-     (loop
-        do (process-updates)))
+     (loop-with-error-backoff #'process-updates))
    :name "process-updates"))

+ 27 - 7
telegram.lisp

@@ -2,19 +2,39 @@
 
 (defvar *telegram-token* nil "Telegram bot token")
 (defparameter +telegram-api-format+ "https://api.telegram.org/bot~A/~A")
+(defvar *telegram-timeout* 30 "Default Telegram timeout")
+
+;; (defun %telegram-api-call (method &optional args)
+;;   (let* ((params (loop for (k . v) in args collect (cons
+;;                                                     (princ-to-string k)
+;;                                                     (princ-to-string v))))
+;;          (response (yason:parse
+;;                    (flexi-streams:octets-to-string
+;;                     (drakma:http-request (format nil +telegram-api-format+ *telegram-token* method)
+;;                                          :method :post
+;;                                          :parameters params
+;;                                          :external-format-out :utf8)
+;;                     :external-format :utf8)
+;;                    :object-as :alist)))
+;;     (unless (aget "ok" response)
+;;       (error (aget "description" response)))
+;;     (aget "result" response)))
 
 (defun %telegram-api-call (method &optional args)
   (let* ((params (loop for (k . v) in args collect (cons
                                                     (princ-to-string k)
                                                     (princ-to-string v))))
+         (timeout (+ 5 (or (cdr (assoc :timeout args))
+                           *telegram-timeout*)))
          (response (yason:parse
-                   (flexi-streams:octets-to-string
-                    (drakma:http-request (format nil +telegram-api-format+ *telegram-token* method)
-                                         :method :post
-                                         :parameters params
-                                         :external-format-out :utf8)
-                    :external-format :utf8)
-                   :object-as :alist)))
+                    (flexi-streams:octets-to-string
+                     (bordeaux-threads:with-timeout (timeout)
+                       (dex:post (format nil +telegram-api-format+ *telegram-token* method)
+                                 :content params
+                                 :use-connection-pool t
+                                 :force-binary t))
+                     :external-format :utf8)
+                    :object-as :alist)))
     (unless (aget "ok" response)
       (error (aget "description" response)))
     (aget "result" response)))

+ 18 - 0
utils.lisp

@@ -1,5 +1,23 @@
 (in-package #:chatikbot)
 
+(defvar *backoff-start* 1 "Initial back-off")
+(defvar *backoff-max* 64 "Maximum back-off delay")
+
+(defun loop-with-error-backoff (func)
+  (let ((backoff *backoff-start*))
+    (loop
+       do
+         (handler-case
+             (progn
+               (funcall func)
+               (setf backoff *backoff-start*))
+           (error (e)
+             (log:error e)
+             (log:info "Backing off for" backoff)
+             (sleep backoff)
+             (setf backoff (min *backoff-max*
+                                (* 2 backoff))))))))
+
 (defun replace-all (string part replacement &key (test #'char=))
   "Returns a new string in which all the occurences of the part
 is replaced with replacement."