Buffered and ranged streams with AzureSDK
Mix.install([
# {:azure_sdk, path: Path.expand("..", __DIR__)},
{:azure_sdk, "~> 0.4.1"}
])
Overview
upload_stream/5 stages Put Block chunks (default 4 MiB) and commits with Put
Block List. download_stream/4 fetches the blob with HTTP Range requests.
Requires Azurite (docker compose up -d). If Blob calls return HTTP 500, the
Azurite data volume is usually corrupted: recreate it with
docker compose down -v && docker compose up -d. If Docker itself reports
overlay I/O errors, restart Docker Desktop, then recreate the volume. As a
workaround you can run
npx azurite --location /tmp/azurite-ex-azure --blobHost 127.0.0.1
on ports 10000–10002.
credential =
AzureSDK.Identity.SharedKeyCredential.new(
"devstoreaccount1",
"Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="
)
client =
AzureSDK.Storage.Client.new(
account: "devstoreaccount1",
credential: credential,
endpoint: "http://127.0.0.1:10000/devstoreaccount1"
)
container = "stream-demo"
case AzureSDK.Storage.Container.exists?(client, container) do
true -> :ok
false -> {:ok, _} = AzureSDK.Storage.Container.create(client, container)
{:error, error} -> raise "Azurite Blob is not reachable: #{error.message}"
end
Stream upload
stream = Stream.repeatedly(fn -> "chunk-data-" end) |> Stream.take(20)
case AzureSDK.Storage.Blob.upload_stream(client, container, "chunks.bin", stream,
block_size: 32
) do
{:ok, _} ->
:ok
{:error, %{status: 500} = error} ->
raise """
Azurite returned HTTP 500 (#{error.message}). Recreate its data volume \
(docker compose down -v && docker compose up -d) or run a temporary \
npx azurite on ports 10000-10002.
"""
{:error, error} ->
raise "upload_stream failed: #{inspect(error)}"
end
Stream download
{:ok, stream} =
AzureSDK.Storage.Blob.download_stream(client, container, "chunks.bin", chunk_size: 64)
stream |> Enum.join() |> byte_size()
Clean up
{:ok, :deleted} = AzureSDK.Storage.Blob.delete(client, container, "chunks.bin")
{:ok, :deleted} = AzureSDK.Storage.Container.delete(client, container)
:ok