2016-07-29 29 views
12

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 

cevap

6

.

burada çözüm pooled_migration anonim işlevinde zaman aşımı yakalamak için, böyle bir şey (Ben Elixir sözdizimi ile çok aşina değilim, bu yüzden derlemek olmayabilir, ama fikir almalısınız):

def pooled_migration(pool, x) do 
:poolboy.transaction(
    pool, 
    (fn(pid) -> 
     try do 
      Migrator.move(pid, { x, @migrator_waiting_time }) 
     catch 
      :exit, reason -> 
      # Ignore error, log it or something else 
      :ok 
     end 
    end), 
    @poolboy_waiting_time 
) 
end 

Zaman aşımına uğrayan Migrator işlemi değil, Migrator çağrısı yapıyor ve biz try-catch gerekir.

Ayrıca, Migrator işleminin hala çalışmıyor olduğunu unutmayın, GenServer call documentation'daki timeouts bölümüne bakın.

GÜNCELLEME: @asiniy ücretsiz Migrator çalışan işlemi beklerken @poolboy_waiting_time yüzden poolboy.transaction işlevi bir zaman aşımı hata atmak değil :infinity ayarlanmalıdır yorumlardaki bahisler gibi. Migrator sonuçta çıkacağından bu güvenlidir.

+0

Çalışma eğilimi! Bu arada, Migrator sürecini burada nasıl öldürebilirim? – asiniy

+0

': 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

+0

Test etmek ve bir ödül vermek için bana birkaç gün ver, tamam mı? – asiniy

İlgili konular