Используйте пул соединений с 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

Это работает, но я не уверен, что это лучший способ решить проблему с подключением, но открыт для других предложений.

Другие вопросы по тегам