मुझे लंबे समय से उपभोग करने वाले माइग्रेशन के साथ समस्या है, जिसे मैं समानांतर में चलाने के लिए वांछित था (इसे समानांतर में चलाया जा सकता है)। दरअसल माइग्रेशन डेटाबेस में सभी रिकॉर्ड लेने और उनमें से प्रत्येक पर संसाधन-उपभोग करने के संचालन को लागू करने के बारे में है।पूलबॉय में टाइमआउट कैसे संभालें?
कभी-कभी व्यक्तिगत रिकॉर्ड माइग्रेशन लटक रहा है, इसलिए मैं समाप्त करने के लिए 10 मिनट देता हूं। अगर माइग्रेशन समाप्त नहीं हुआ है, तो मैं इसे बिना किसी अपवाद के नीचे बंद कर देना चाहता हूं (नीचे देखें)
मैं प्रवासन को समानांतर करने के लिए poolboy एरलांग पैकेज का भी उपयोग कर रहा हूं क्योंकि माइग्रेशन न केवल समय का उपभोग करता है, बल्कि संसाधन भी। समस्या यह है कि मुझे नहीं पता कि टाइमआउट होने पर त्रुटि को कैसे संभालना है और कोड तोड़ने जा रहा है। मेरे पर्यवेक्षण पेड़ है:
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
समस्या है, तो डेटाबेस में कुछ रिकॉर्ड के प्रवास से अधिक 10 मिनट मैं अपवाद के इस प्रकार है लेता है:
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]}}
मैं Migrator
को terminate/2
या handle_info/2
डालने की कोशिश की और इसके साथ खेलते हैं, लेकिन मैं इन कार्यों को भी शामिल नहीं किया गया है। मैं टाइमआउट कैसे संभाल सकता हूं और उन्हें अपने माइग्रेशन को तोड़ने से रोक सकता हूं?
मैं @ johlo के संकेत इस्तेमाल किया अद्यतन, लेकिन मैं अभी भी समय हो रही है बाहर। मेरे समारोह है:
def init(_) do
Process.flag(:trap_exit, true)
{:ok, %{}}
end
यह काम करता है! वैसे, मैं यहां 'माइग्रेटर' प्रक्रिया को कैसे मार सकता हूं? – asiniy
'निकास' को पकड़ते समय आप 'Process.exit/2] (http://elixir-lang.org/docs/stable/elixir/Process.html#exit/2) का उपयोग' 'kill 'भेजने के लिए कर सकते हैं 'माइग्रेटर' को संकेत दें। या आप इसे एक सामान्य 'जेनसेवर' संदेश भेज सकते हैं जो इसे रोकने के लिए कह रहा है, लेकिन यह केवल 'चाल' कार्य के साथ किया जाने पर संसाधित हो जाएगा। – johlo
मुझे परीक्षण करने के लिए दो दिन दें और एक बक्षीस सौंपें, ठीक है? – asiniy