[Python] 移动等待时间
考虑一种需求,client 向 server 发送一个请求,server 因为某种原因没有回复,或者回复失败。client 接受失败后等待一段时间;第二次再次请求,仍然失败,此时你想要根据连续失败次数延长等待时间;在每一次成功之后确定等待的时间不变(比如为 0)。
running_wait-time
有几种方案可以实现这种需要,根据 python 的闭包特性,编写一个 function 而非编写 class 就可以实现这个需求。1
完整代码在 github 上的链接
Server 端的代码通过 IPC 为 Client 提供服务,本 需求-solution 重在说明 Client 行为,Server 端代码是本主题不关心的。但是也放上来以供参考。
Client
详细实现细节/原理待有空 更新。
#!/usr/bin/env python3
"""
Author: Joseph Lin
E-mail: joseph.lin@aliyun.com
Social: https://github.com/RDpWTeHM
https://me.csdn.net/qq_29757283
"""
import sys
# import os
from multiprocessing.connection import Client
# import time
from time import ctime
from time import sleep
def main():
missions = [#"localhost", "google.com", "bing.com", "github.com",
#"www.csdn.net",
"yahoo.com", "google.com", "www.jd.com", "www.baidu.com",
"www.amazon.com", "www.gitee.com",
]
def timeoutsleep():
_totimes = 0
def runningsleep(IsTimeout):
nonlocal _totimes # fluent python - & 7.6 nonlocal
if IsTimeout is False:
_totimes = 0
elif IsTimeout is True:
_totimes += 1
if __debug__: sleep(_totimes * 2)
else: sleep(_totimes * 5)
else:
raise Exception("<timeoutsleep> Error parameter gived!")
return runningsleep
tosleep = timeoutsleep()
cconn = Client(("localhost", 15337), authkey=b"running_wait-time")
try:
for mission in missions:
cconn.send("http://" + mission)
page_source = cconn.recv()
if "timeout" == page_source.lower():
print("[{}] timeout in {}!".format(ctime(), mission))
tosleep(True)
else:
print("[{}] get {} suucess!".format(ctime(), mission))
tosleep(False)
except EOFError:
print("Server closed the IPC connection!", file=sys.stderr)
raise SystemExit("Mission Interrupt due to server closed connection!")
else:
cconn.close()
if __name__ == "__main__":
main()
Server
- bug detect - 需要两次 Ctrl+C 才能完全退出程序。
Server 端在 browser 运行.get()
期间,接收到 SIGTERM/SIGINT 会被 selenium 库代码捕获,以至于不能正常执行我们编写的捕获 SIG* 运行代码。
但是该 bug 目前对本 blog 要实现的功能无关,且不影响测试功能,暂时未解决。
#!/usr/bin/env python3
"""
Author: Joseph Lin
E-mail: joseph.lin@aliyun.com
Social: https://github.com/RDpWTeHM
https://me.csdn.net/qq_29757283
"""
import os
import sys
# import time
from time import ctime
# from time import sleep
import signal
from multiprocessing.connection import Listener
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
PATH = os.environ.get("PATH", None)
os.environ['PATH'] = "/usr/lib/chromium-browser:" + PATH
browser = webdriver.Chrome()
browser_bkup = browser # just in case lost browser banding.
browser.implicitly_wait(20)
browser.set_script_timeout(20) # lower timeout can be easy to
browser.set_page_load_timeout(20)
def handler_client(conn):
while True: # handle client until client close the connection
try:
recv = conn.recv()
except EOFError:
print("Connection closed at {}".format(ctime()))
break
except Exception as e: # 如何在测试中跑到这个 condition???
print("[Error] Unexcept Exception: ", e, file=sys.stderr)
print("\tclose connection but not exit program!", file=sys.stderr)
conn.close()
break
else:
try:
print("[{}][INFO] request {}".format(ctime(), recv))
safe_get_tab = browser.window_handles[0]
excute_script_str = "window.open('{}','handler_tab');".format("about:blank")
browser.execute_script(excute_script_str)
browser.switch_to.window('handler_tab')
browser.get(recv)
except TimeoutException as e:
print("[{}][WARNING] get '{}' page source timeout!".format(ctime(), recv))
print("\t", "=" * 15, "TimeoutException: ", "=" * 15, "\n", e)
# browser.execute_script("window.stop();")
page_source = "timeout"
else:
print("[{}][INFO] finish get '{}' page source".format(ctime(), recv))
page_source = browser.page_source
finally:
browser.close()
browser.switch_to.window(safe_get_tab)
conn.send(page_source)
def server_handler(address, authkey):
serv = Listener(address, authkey=authkey)
while True: # server act like daemon
try:
client_conn = serv.accept()
handler_client(client_conn)
except Exception:
import traceback; traceback.print_exc()
def handler_everything():
server_handler(("", 15337), authkey=b"running_wait-time")
def main():
def sigterm_handler(signo, frame):
# close the connection - use global queue!!!!
browser_bkup.quit()
raise SystemExit("\nreceive 'Ctrl+C'/'kill -15'/SIGTERM, program stop!")
signal.signal(signal.SIGINT, sigterm_handler)
signal.signal(signal.SIGTERM, sigterm_handler)
try:
handler_everything()
except Exception as e: # 报告一切错误
print("[Error] Exception: ", e, file=sys.stderr)
if __name__ == "__main__":
main()
Reference
Fluent Python (流畅的 Python)&7.6 ↩︎