我正在尝试为单元测试创建一个Redis临时实例:
class RedisTemporaryInstance:
def __enter__(self):
self.process = subprocess.Popen(['redis-server', '--port', '6399'],
stdout=open(os.devnull, 'wb'),
stderr=subprocess.STDOUT)
return self
def __exit__(self, exc_type, exc_value, traceback):
subprocess.call(['redis-cli', '-p', '6399', 'shutdown'])
但是当我这样使用它时:
import redis
with RedisTemporaryInstance() as temp:
red = redis.Redis(port=6399)
print(red.ping())
我正在
ConnectionError: Error 111 connecting to localhost:6399. Connection refused.
然而,当我加入一个小睡眠时
with RedisTemporaryInstance() as temp:
sleep(0.01)
red = redis.Redis(port=6399)
print(red.ping())
一切正常。显然,服务器尚未准备好接受没有睡眠的连接。
我的问题是:是否有更好的方法等待服务器准备就绪而不是添加任意睡眠持续时间?
答案 0 :(得分:1)
您应该等待服务器初始化,作为输入方法的一部分。 您可以使用帮助程序方法检查打开的端口:
def check_socket(host, port):
import socket
from contextlib import closing
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
if sock.connect_ex((host, port)) == 0:
return True
else:
return False
class RedisTemporaryInstance:
def __enter__(self):
self.process = subprocess.Popen(['redis-server', '--port', '6399'],
stdout=open(os.devnull, 'wb'),
stderr=subprocess.STDOUT)
retries = 5
while not check_socket('127.0.0.1', 6399) and retries > 0:
sleep(0.1)
retries -= 1
if retries == 0:
print 'failure'
return self
这样,只有在初始化后才能获得Redis对象
答案 1 :(得分:0)
您使用Popen启动redis服务器。这需要花费时间(在您的情况下为0.01秒),因为打开了进程并与您的接口进行了监听连接。 Popen是非阻塞的,因此命令将在您的系统上设置,代码继续。这是with
语句在redis-server启动之前完成的时间。我认为你必须在启动redis服务器后在阻塞调用中使用redis-cli ping
(subprocess.call
):
class RedisTemporaryInstance:
def __enter__(self):
self.process = subprocess.Popen(['redis-server', '--port', '6399'],
stdout=open(os.devnull, 'wb'),
stderr=subprocess.STDOUT)
subprocess.call(['redis-cli', '-p', '6399', 'ping'])
return self
def __exit__(self, exc_type, exc_value, traceback):
subprocess.call(['redis-cli', '-p', '6399', 'shutdown'])