Paralel olarak çalışmak istediğim uzun süreli bir taşıma işleminde sorun yaşıyorum (paralel olarak çalıştırılabilir). Aslında göç, veritabanındaki tüm kayıtları almak ve her birinde zaman ve kaynak tüketen işlemleri uygulamakla ilgilidir.Poolboy'da zaman aşımları nasıl ele alınır?
Bazen tek tek kayıt geçişi takılıyor, bu yüzden bitirmem 10 dakika veriyorum. göç bitmiş değilse, bunu incelikle ben de göç sadece zaman tüketir beri uygulanmasını paralel hale poolboy erlang paketini kullanıyorum
(aşağıya bakınız) herhangi istisnasız kapatmaya istiyorum, ama kaynaklar da. Sorun şu ki zaman aşımı olduğunda hata nasıl işleneceğini bilmiyorum ve kod kırılacak. Benim denetim ağacı:
defmodule MyReelty.Repo.Migrations.MoveVideosFromVimeoToB2 do
use Ecto.Migration
alias MyReelty.Repo
alias MyReelty.Repo.Migrations.MoveVideosFromVimeoToB2.Migrator
# parallel nature of migration force us to disable transaction
@disable_ddl_transaction true
@migrator_waiting_time 10 * 60 * 1000 # timeout
@poolboy_waiting_time @migrator_waiting_time + 10 * 1000 # give a time for graceful shutdown
@pool_name :migrator
@pool_size 3
@pool_config [
{ :name, { :local, @pool_name }},
{ :worker_module, Migrator },
{ :size, @pool_size },
{ :max_overflow, 0 },
{ :strategy, :fifo }
]
def up do
children = [
:poolboy.child_spec(@pool_name, @pool_config)
]
opts = [strategy: :one_for_one, name: MyReelty.Supervisor]
Supervisor.start_link(children, opts)
rows = Review |> Repo.all
IO.puts "Total amount of reviews is: #{length(rows)}"
parallel_migrations(rows)
end
def parallel_migrations(rows) do
Enum.map(rows, fn(row) ->
pooled_migration(@pool_name, row)
end)
end
def pooled_migration(pool, x) do
:poolboy.transaction(
pool,
(fn(pid) -> Migrator.move(pid, { x, @migrator_waiting_time }) end),
@poolboy_waiting_time
)
end
defmodule Migrator do
alias MyReelty.Repo
alias MyReelty.Review
use GenServer
def start_link(_) do
GenServer.start_link(__MODULE__, nil, [])
end
def move(server, { params, waiting_time }) do
GenServer.call(server, { :move, params }, waiting_time)
end
def handle_call({ :move, result }, _from, state) do
big_time_and_resource_consuming_task_here
{:reply, %{}, state}
end
end
end
veritabanında bazı kaydın göç ben hariç bu tür var fazla 10 dakika sürer eğer sorun:
20:18:16.917 [error] Task #PID<0.282.0> started from #PID<0.70.0> terminating
** (stop) exited in: GenServer.call(#PID<0.278.0>, {:move, [2, "/videos/164064419", "w 35th st Springfield United States Illinois 60020"]}, 60000)
** (EXIT) time out
(elixir) lib/gen_server.ex:604: GenServer.call/3
(poolboy) src/poolboy.erl:76: :poolboy.transaction/3
(elixir) lib/task/supervised.ex:94: Task.Supervised.do_apply/2
(elixir) lib/task/supervised.ex:45: Task.Supervised.reply/5
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Function: #Function<5.53617785/0 in MyReelty.Repo.Migrations.MoveVideosFromVimeoToB2.parallel_migrations/1>
Args: []
20:18:16.918 [error] GenServer MyReelty.Repo terminating
** (stop) exited in: GenServer.call(#PID<0.278.0>, {:move, [2, "/videos/164064419", "w 35th st Springfield United States Illinois 60020"]}, 60000)
** (EXIT) time out
Last message: {:EXIT, #PID<0.70.0>, {:timeout, {GenServer, :call, [#PID<0.278.0>, {:move, [2, "/videos/164064419", "w 35th st Springfield United States Illinois 60020"]}, 60000]}}}
State: {:state, {:local, MyReelty.Repo}, :one_for_one, [{:child, #PID<0.231.0>, DBConnection.Poolboy, {:poolboy, :start_link, [[name: {:local, MyReelty.Repo.Pool}, strategy: :fifo, size: 1, max_overflow: 0, worker_module: DBConnection.Poolboy.Worker], {Postgrex.Protocol, [types: true, username: "adik", types: true, name: MyReelty.Repo.Pool, otp_app: :my_reelty, repo: MyReelty.Repo, adapter: Ecto.Adapters.Postgres, database: "my_reelty_dev", hostname: "localhost", extensions: [{Geo.PostGIS.Extension, [library: Geo]}, {Ecto.Adapters.Postgres.DateTime, []}, {Postgrex.Extensions.JSON, [library: Poison]}], pool_size: 1, pool_timeout: 5000, timeout: 15000, adapter: Ecto.Adapters.Postgres, database: "my_dev", hostname: "localhost", pool_size: 10, pool: DBConnection.Poolboy, port: 5432]}]}, :permanent, 5000, :worker, [:poolboy]}], :undefined, 3, 5, [], 0, Ecto.Repo.Supervisor, {MyReelty.Repo, :my_reelty, Ecto.Adapters.Postgres, [otp_app: :my_reelty, repo: MyReelty.Repo, adapter: Ecto.Adapters.Postgres, database: "my_reelty_dev", hostname: "localhost", extensions: [{Geo.PostGIS.Extension, [library: Geo]}], pool_size: 1]}}
Ben Migrator
için terminate/2
veya handle_info/2
eklemek için çalıştı ve onunla oynayın, ama çağırılmak üzere bu işlevlere bile ulaşmadım. Zaman aşımlarını nasıl ele alabilirim ve göçümü kırmalarını nasıl engelleyebilirim?
Ben @ johlo en ipucu kullanılan
GÜNCELLEME, ama yine de zaman çıkıyorum. Benim fonksiyonudur: bu GenServer
çağrı yapan gerçek bir süreç beri bunun dışında Migrator.move/2
(yani GenServer.call
) işlevi kez tüm MoveVideosFromVimeoToB2
işlemin kilitlenmesine
def init(_) do
Process.flag(:trap_exit, true)
{:ok, %{}}
end
Çalışma eğilimi! Bu arada, Migrator sürecini burada nasıl öldürebilirim? – asiniy
': exit' 'u yakalarken,' 'kill'' göndermek için [Process.exit/2] 'yi (http://elixir-lang.org/docs/stable/elixir/Process.html#exit/2) kullanabilirsiniz. Migrator'a sinyal. Ya da bunu durdurmak için söylüyorum sıradan bir 'GenServer' mesajı gönderebilirsiniz, ancak bu sadece önceki' move' görevi ile bittiğinde işlenecektir. – johlo
Test etmek ve bir ödül vermek için bana birkaç gün ver, tamam mı? – asiniy