OTP로 Elixir에 주기적인 작업 추가하기

이번 포스팅에서는 Elixir OTP를 이용하여 간단한 주기적 태스크를 생성하는 방법을 보여드리겠습니다.

이 예에서는 간단한 서버 계산기를 만듭니다. 어쨌든 시간이 지남에 따라 주기적으로 숫자를 계속 추가하고 싶습니다. 이 프로세스의 초기 구조는 다음과 같습니다.

defmodule Calculator do
  use GenServer

  @doc """
  Starts the calculator.
  """
  def start_link(opts) do
    GenServer.start_link(__MODULE__, :ok, opts)
  end

  @impl true
  def init(:ok) do
    IO.puts("starting calculator")
    {:ok, 0}
  end

  @impl true
  def handle_call({:add, num}, _from, state) do
    result = state + num
    IO.puts(result)
    {:reply, {:ok, result}, result}
  end

  def add(server, num) do
    {:ok, result} = GenServer.call(server, {:add, num})
    result
  end
end


여기에서 서버에 메시지{:add, num}를 전송하여 번호를 추가할 수 있습니다. 이를 위한 클라이언트 기능은 add/2 입니다.

그런 다음 주기적인 작업을 처리할 새 프로세스를 만들어야 합니다.

defmodule Periodic do
  use GenServer

  defstruct freq: nil, server: nil, callback: nil

  def start_link(opts) do
    GenServer.start_link(__MODULE__, :ok, opts)
  end

  @impl true
  def init(:ok) do
    {:ok, %{}}
  end

  @impl true
  def handle_call({:periodic, data}, _from, state) do
    Process.send_after(data.server, {:tick, data}, data.freq)

    {:reply, data, state}
  end

  @impl true
  def handle_info({:tick, data}, state) do
    data.callback.()

    Process.send_after(data.server, {:tick, data}, data.freq)

    {:noreply, state}
  end

  def retry(server, data) do
    data = Map.put(data, :server, server)
    GenServer.call(data.server, {:periodic, data})
  end
end


주기적 작업은 Process.send_after/3 함수를 사용하여 생성됩니다. 이렇게 하면 {:tick, data}ms의 시간 후에 메시지data.freq가 서버로 전송됩니다.

이 서버의 기본 개념은 클라이언트가 역시 클라이언트가 정의한 빈도(ms)로 주기적으로 실행되는 기능callback을 제공해야 한다는 것입니다. 따라서 클라이언트는 callbackfreq 의 두 가지 입력을 제공해야 합니다.

주기적 작업을 실행하기 위해 클라이언트는 retry/2callback 정보를 전달하여 freq 함수를 호출해야 합니다.

마지막으로 Calculator 서버에서 실행해야 하는 주기적 작업을 정의해야 합니다. 우리는 주기적으로 숫자를 계속 추가하고 싶다는 점을 기억하십시오. 이를 위해 add_periodic 모듈에서 새 함수freq와 상수Calculator(1000ms로 설정)를 정의합니다.

defmodule Calculator do
  ...
  alias Periodic

  @freq 1000

  def add_periodic(server, num, freq \\ @freq) do
    {:ok, pid} = Periodic.start_link([])

    callback = fn -> add(server, num) end

    Periodic.retry(pid, %Periodic{freq: freq, callback: callback})
  end


전체 코드는 HERE에서 찾을 수 있습니다.


사용 예:



먼저 다음을 수행하여 iex 쉘을 엽니다.

iex -S mix


그 다음에,

import Calculator

{:ok, pid} = Calculator.start_link([])

Calculator.add_periodic(pid, 2)


그리고 짜잔, 우리는 다음과 같은 것을 보게 될 것입니다:

2
4
6
8
...

좋은 웹페이지 즐겨찾기