Используйте пул соединений с python sshfs (fsspec) в Python
Я использую sshfs для извлечения видеофайлов из удаленного хранилища SSH:
@app.get("/video/{filename}")
async def video_endpoint(
filename, range: str = Header(None), db=Depends(get_db)
): # pylint: disable=redefined-builtin
"""
Endpoint for video streaming
Accepts the UUID and an arbitrary extension
"""
# Requesting video with uuid
(uuid, extension) = filename.split(".") # pylint: disable=unused-variable
# Try to get the file info from database
file = File.get_by_public_uuid(db, uuid)
# Return 404 if file not found
if not file:
raise HTTPException(404, "File not found")
# Connect with a password
ssh_fs = SSHFileSystem(
settings.ssh_host,
username=settings.ssh_username,
password=settings.ssh_password,
)
start, end = range.replace("bytes=", "").split("-")
start = int(start)
end = int(end) if end else start + settings.chunk_size
with ssh_fs.open(file.path) as video:
video.seek(start)
data = video.read(end - start)
filesize = file.size
headers = {
"Content-Range": f"bytes {str(start)}-{str(end)}/{filesize}",
"Accept-Ranges": "bytes",
}
return Response(data, status_code=206, headers=headers, media_type="video/mp4")
Он работает в течение нескольких часов после перезапуска, но затем последующие вызовы выдают сообщение об ошибке.asyncssh.sftp.SFTPNoConnection: Connection not open
. Насколько я могу судить, хотяSSHFileSystem
инициируется во время вызова API, он фактически кэшируется в бэкэнде.
Fsspec создает некоторый цикл событий asyncio и возвращает кэшированный экземпляр. Я предполагаю, что в какой-то момент соединение прерывается другой стороной, и по какой-то причине оно не восстанавливается автоматически, и я не могу найти способ использовать пул соединений.
Я могу избежать ошибки, позвонивssh_fs.clear_instance_cache()
в конце, но это означает, что каждый раз устанавливается новое соединение, и это для каждого извлеченного фрагмента, что также не имеет смысла.
Мой вопрос: как использоватьSFTPNoConnection
пул соединений таким образом, чтобы поддерживать соединение и восстанавливать его при необходимости?
1 ответ
Я каким-то образом решил проблему, обернув установление соединения SSH и вручную обработав исключения, очистив кеш экземпляра и повторно подключившись:
def get_ssh_fs():
"""
Get the SSH FileSystem
"""
error_count = MAX_CONNECTION_ATTEMPTS
while error_count > 0:
# This will used the cached instance by default, so return should be fast
ssh_fs = SSHFileSystem(
settings.ssh_host,
username=settings.ssh_username,
password=settings.ssh_password,
)
# Check if the connection is still alive
try:
ssh_fs.du("/")
return ssh_fs
except asyncssh.sftp.SFTPNoConnection as e:
# Connection is lost, clear the instance cache and try again
logging.warning("SSH Connection lost, reconnecting. Exception: %s", e)
ssh_fs.clear_instance_cache()
error_count -= 1
logging.error("Could not reconnect to SSH server")
return None
Это работает, но я не уверен, что это лучший способ решить проблему с подключением, но открыт для других предложений.