这是我的第一个Elixir / Phoenix项目,到目前为止我很喜欢它。可悲的是,我还没有多少时间真正探索任务/并发或otp。
我有一张表格,一次最多可以上传7张图片。我最初设置代码同步上传这些,1乘1.我的下一次迭代是尝试并行运行这些,这可以在下面的upload_many
函数中看到。
上传7 x 250kb图像所花费的总时间并没有缩短(约15秒),重新写入,这清楚地表明我做错了什么。
我真的很感激任何帮助或建议。
defmodule MyApp.S3 do
def upload_many(params, keys) do
ops = [max_concurrency: System.schedulers_online() * 3, timeout: 20000]
keys
# [{"passport_image_url", file}, {"drivers_license_url", file2}, ...]
|> Task.async_stream(&upload/1, ops)
|> Enum.to_list()
end
def upload({url_key, image_params}) do
unique_filename = get_unique_filename(image_params.filename)
case File.read(image_params.path) do
{:error, _} ->
{:error, url_key, "file could not be read"}
{:ok, image_binary} ->
# returns image url string or error
res = put_object(unique_filename, image_binary)
IO.inspect url_key
Tuple.insert_at(res, 1, url_key)
# {:ok, url_key, url}
end
end
def get_unique_filename(filename) do
file_uuid = UUID.uuid4(:hex)
image_filename = filename
"#{file_uuid}-#{image_filename}"
end
def put_object(unique, image_binary) do
bucket = System.get_env("BUCKET_NAME")
res = ExAws.S3.put_object(bucket, unique, image_binary)
|> ExAws.request!
case res do
%{status_code: 200} ->
{:ok, image_url(unique, bucket)}
_ ->
{:error, "error uploading to S3"}
end
end
def image_url(unique, bucket) do
"https://#{bucket}.s3.amazonaws.com/#{bucket}/#{unique}"
end
end
我已经编写了一个上传7张图片的测试,并且使用ExAws
模拟了Process.sleep(4000); %{status_code: 200}
请求,并使用 test "updates startpack with many file uploads", %{conn: conn, user: user} do
startpack = Repo.insert! %Startpack{user_id: user.id}
image_upload = %Plug.Upload{path: "test/fixtures/foxy.png", filename: "foxy.png"}
# possible solution for multiple fields
images = %{
"passport_image" => image_upload,
"vehicle_insurance_image" => image_upload,
"box_rental_image" => image_upload,
"equipment_rental_image" => image_upload,
"p45_image" => image_upload,
"schedule_d_letter_image" => image_upload,
"loan_out_company_cert_image" => image_upload
}
valid = Map.merge(@valid_attrs, images)
with_mock ExAws, [request!: fn(_) ->
Process.sleep(4000)
%{status_code: 200}
end] do
conn = put conn, startpack_path(conn, :update, startpack), startpack: valid
assert redirected_to(conn) == startpack_path(conn, :show, startpack)
startpack = Repo.get_by(Startpack, user_id: user.id)
assert startpack.passport_url
end
end
进行了操作。使用4秒模拟,它可以在4秒内同时执行7个任务,但如果我删除模拟并上传真实文件,则需要大约15秒钟。这是测试:
<field src="/my_module/static/src/img/my_image.png"/>