如何优雅地处理请求中的连接错误? [英] How to handle a connection error gracefully in requests?

查看:37
本文介绍了如何优雅地处理请求中的连接错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的 python 电报机器人,代码如下:

导入请求导入json从时间导入睡眠导入操作系统文件名 = 'bot_last_update'目标 = 打开(文件名,'r')update_from_file = target.read()# 检查文件更新update_from_file = update_from_file.strip()last_update = int(update_from_file)令牌 = xxxxurl = 'https://api.telegram.org/bot%s/' % 令牌# 我们想继续检查更新.所以这一定是一个永无止境的循环为真:# 我的聊天功能正常运行,我需要维护它!为我获取所有聊天更新get_updates = json.loads(requests.get(url + 'getUpdates').content)# 好的,我有.让我们遍历每一个对于 get_updates['result'] 中的更新:# 首先确保我还没有阅读此更新如果 last_update <更新['update_id']:last_update = 更新['update_id']目标 = 打开(文件名,'w')target.truncate()target.write(str(last_update))目标.关闭()如果更新['message']['chat']['type'] == 'private':# 我有一个新的更新.让我们看看它是什么.if update['message']['text'] == 'do something':requests.get(url + 'sendMessage', params=dict(chat_id=update['message']['chat']['id'], text='doing it'))os.system('/srv/scripts/do_something.sh')睡觉(10)requests.get(url + 'sendMessage', params=dict(chat_id=update['message']['chat']['id'], text='done!'))别的:经过#让我们等待几秒钟的新更新睡觉(1)

它工作正常,但每次我的网络出现问题时都会出现此错误:

回溯(最近一次调用最后一次):文件my_telegram_bot.py",第 21 行,在 <module> 中get_updates = json.loads(requests.get(url + 'getUpdates').content)文件/usr/local/lib/python2.7/dist-packages/requests/api.py",第70行,在get返回请求('get', url, params=params, **kwargs)文件/usr/local/lib/python2.7/dist-packages/requests/api.py",第56行,请求返回 session.request(method=method, url=url, **kwargs)文件/usr/local/lib/python2.7/dist-packages/requests/sessions.py",第475行,请求resp = self.send(prep, **send_kwargs)文件/usr/local/lib/python2.7/dist-packages/requests/sessions.py",第596行,发送r = adapter.send(request, **kwargs)文件/usr/local/lib/python2.7/dist-packages/requests/adapters.py",第473行,发送引发连接错误(错误,请求=请求)requests.exceptions.ConnectionError: ('Connection aborted.', error(113, 'No route to host'))

避免该错误的最佳方法是什么?我想一直保持这个机器人,所以它不应该在这些类型的事件中以严重的方式失败(或者如果它失败了,它应该自动恢复/重新启动).

解决方案

需要实现重试机制.这是python中的一个例子如何在python异常后重试?.假设连接在合理的时间内自行纠正,重试机制将保持机器人运行并避免错误.

查看 Python 请求异常处理以获取捕获特定异常的示例.>

结合我们得到的两个例子:

 from requests import ConnectionError进口请求导入json导入时间导入操作系统connection_timeout = 30 # 秒

...

#我的聊天功能正常运行,我需要维护它!为我获取所有聊天更新start_time = time.time()为真:尝试:get_updates = json.loads(requests.get(url + 'getUpdates').content)休息除了连接错误:如果 time.time() >开始时间 + 连接超时:raise Exception('Unable to get updates after {} seconds of ConnectionErrors'.format(connection_timeout))别的:time.sleep(1) # 每秒尝试一次# 好的,我有.让我们遍历每一个

...

这将重试每秒调用 getUpdates 30 秒,直到连接权限本身.您可以根据需要将 connection_timeout 调整为大或小,以覆盖间歇性连接.

I have a simple python telegram bot, here's the code:

import requests
import json
from time import sleep
import os

filename = 'bot_last_update'
target = open(filename, 'r')
update_from_file = target.read()

# check update from file
update_from_file = update_from_file.strip()
last_update = int(update_from_file)

token = xxxx
url = 'https://api.telegram.org/bot%s/' % token

# We want to keep checking for updates. So this must be a never ending loop
while True:
    # My chat is up and running, I need to maintain it! Get me all chat updates
    get_updates = json.loads(requests.get(url + 'getUpdates').content)
    # Ok, I've got 'em. Let's iterate through each one
    for update in get_updates['result']:
        # First make sure I haven't read this update yet
        if last_update < update['update_id']:
            last_update = update['update_id']
            target = open(filename, 'w')
            target.truncate()
            target.write(str(last_update))
            target.close()
            if update['message']['chat']['type'] == 'private':
            # I've got a new update. Let's see what it is.
                if update['message']['text'] == 'do something':
                    requests.get(url + 'sendMessage', params=dict(chat_id=update['message']['chat']['id'], text='doing it'))
                    os.system('/srv/scripts/do_something.sh')
                    sleep(10)
                    requests.get(url + 'sendMessage', params=dict(chat_id=update['message']['chat']['id'], text='done!'))
                else:
                    pass
    # Let's wait a few seconds for new updates
    sleep(1)

It works fine but every time I have some problem in my network I have this error:

Traceback (most recent call last):
  File "my_telegram_bot.py", line 21, in <module>
    get_updates = json.loads(requests.get(url + 'getUpdates').content)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 70, in get
    return request('get', url, params=params, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 56, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 475, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 596, in send
    r = adapter.send(request, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py", line 473, in send
    raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', error(113, 'No route to host'))

What would be the best way to avoid that error ? I would like to keep this bot up at all times, so it should not fail in a critical way during those kinds of events (or if it does, it should auto-recover / restart by itself).

解决方案

You need to implement a retry mechanism. Here is an example in python How to retry after exception in python?. A retry mechanism will keep the bot up and avoid the error assuming the connection corrects itself in a reasonable amount of time.

Check out Python requests exception handling for an example of catching your specific exception.

Combining the two examples we get:

from requests import ConnectionError
import requests
import json
import time
import os
connection_timeout = 30 # seconds

...

# My chat is up and running, I need to maintain it! Get me all chat updates
start_time = time.time()
while True:
    try:
        get_updates = json.loads(requests.get(url + 'getUpdates').content)
        break
    except ConnectionError:
        if time.time() > start_time + connection_timeout:
            raise Exception('Unable to get updates after {} seconds of ConnectionErrors'.format(connection_timeout))
        else:
            time.sleep(1) # attempting once every second
# Ok, I've got 'em. Let's iterate through each one

...

This will retry calling getUpdates every second for 30 seconds until the connection rights itself. You can tune the connection_timeout to be as big or small as needed in order to cover the intermittent connection.

这篇关于如何优雅地处理请求中的连接错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆