From c6f6056ed2c597c99917939e9fb560d6ff8daae3 Mon Sep 17 00:00:00 2001 From: Adriano Santos Date: Mon, 30 Sep 2024 11:36:54 -0300 Subject: [PATCH] Refactor to use protocol --- lib/actors/actor/entity/entity.ex | 16 ++--- lib/spawn/cluster/provisioner/executor.ex | 4 ++ lib/spawn/cluster/provisioner/scheduler.ex | 66 ++++++++++++++++++++- lib/spawn/cluster/provisioner/spawn_task.ex | 3 + 4 files changed, 79 insertions(+), 10 deletions(-) create mode 100644 lib/spawn/cluster/provisioner/executor.ex create mode 100644 lib/spawn/cluster/provisioner/spawn_task.ex diff --git a/lib/actors/actor/entity/entity.ex b/lib/actors/actor/entity/entity.ex index c9c2b86c..b364cc6f 100644 --- a/lib/actors/actor/entity/entity.ex +++ b/lib/actors/actor/entity/entity.ex @@ -83,6 +83,7 @@ defmodule Actors.Actor.Entity do alias Eigr.Functions.Protocol.State.Revision alias Spawn.Cluster.Provisioner.Scheduler + alias Spawn.Cluster.Provisioner.SpawnTask import Spawn.Utils.Common, only: [return_and_maybe_hibernate: 1] @@ -152,13 +153,14 @@ defmodule Actors.Actor.Entity do # The same applies to asynchronous calls. case kind do :TASK -> - Scheduler.schedule_and_invoke( - actor_name, - invocation, - opts, - state, - &Invocation.invoke/2 - ) + task = %SpawnTask{ + parent: actor_name, + invocation: invocation, + opts: opts, + state: state + } + + Scheduler.schedule_and_invoke(task, &Invocation.invoke/2) _ -> Invocation.invoke({invocation, opts}, state) diff --git a/lib/spawn/cluster/provisioner/executor.ex b/lib/spawn/cluster/provisioner/executor.ex new file mode 100644 index 00000000..01feb3fa --- /dev/null +++ b/lib/spawn/cluster/provisioner/executor.ex @@ -0,0 +1,4 @@ +defprotocol Spawn.Cluster.Provisioner.Executor do + @doc "Executes a task" + def execute(task, func) +end diff --git a/lib/spawn/cluster/provisioner/scheduler.ex b/lib/spawn/cluster/provisioner/scheduler.ex index bc1e649d..e9bdd48d 100644 --- a/lib/spawn/cluster/provisioner/scheduler.ex +++ b/lib/spawn/cluster/provisioner/scheduler.ex @@ -1,9 +1,69 @@ defmodule Spawn.Cluster.Provisioner.Scheduler do + @moduledoc """ + The `Spawn.Cluster.Provisioner.Scheduler` module is responsible for scheduling tasks and invoking functions in a distributed actor system. + It handles creating worker pools and executing functions with the given task configuration. + + This module also contains an implementation of the `Executor` protocol for the `SpawnTask` struct, + defining the execution behavior for tasks in the context of provisioning actors in the cluster. + """ + + alias Spawn.Cluster.Provisioner.SpawnTask alias Spawn.Cluster.ProvisionerPoolSupervisor import Spawn.Utils.Common, only: [build_worker_pool_name: 2] - def schedule_and_invoke(parent, invocation, opts, state, func) when is_function(func) do - build_worker_pool_name(ProvisionerPoolSupervisor, parent) - |> FLAME.call(fn -> func.({invocation, opts}, state) end) + @doc """ + Defines the `Executor` protocol for the `SpawnTask` struct. + + This implementation handles the execution of a given function (`func`) in the context of a task, + using the specified parent, invocation details, options (`opts`), and state. + + The task is executed through a worker pool, created using the `build_worker_pool_name/2` function, + and the function is invoked with the `{invocation, opts}` tuple and the current state. + + ## Parameters + + - `%SpawnTask{}`: The task struct containing details about the actor provisioning process. + - `func`: The function to be invoked, which takes the task's `invocation`, `opts`, and `state`. + + ## Returns + + The result of executing the provided function within the context of the actor provisioning system. + """ + defimpl Spawn.Cluster.Provisioner.Executor, for: Spawn.Cluster.Provisioner.SpawnTask do + def execute(%SpawnTask{parent: parent, invocation: invocation, opts: opts, state: state}, func) + when is_function(func) do + build_worker_pool_name(ProvisionerPoolSupervisor, parent) + |> FLAME.call(fn -> func.({invocation, opts}, state) end) + end + end + + @doc """ + Schedules and invokes a task for actor provisioning in another k8s POD. + + This function wraps the scheduling logic by leveraging the `Executor` protocol to execute the provided + function (`func`). The function is called with the `invocation`, `opts`, and `state` details encapsulated in a `SpawnTask` struct. + + ## Parameters + + - `parent`: The parent reference used to create the worker pool for the task execution. + - `invocation`: The details of the invocation, typically containing metadata about the actor's execution. + - `opts`: Options passed along with the task, which may modify how the invocation is performed. + - `state`: The current state of the process, to be passed to the function being invoked. + - `func`: A function that will be called with the `{invocation, opts}` tuple and the current `state`. + + ## Example + + ```elixir + task = %SpawnTask{ + parent: parent, + invocation: invocation, + opts: opts, + state: state + } + + Spawn.Cluster.Provisioner.Scheduler.schedule_and_invoke(task, &some_function/2) + """ + def schedule_and_invoke(task, func) when is_function(func) do + Spawn.Cluster.Provisioner.Executor.execute(task, func) end end diff --git a/lib/spawn/cluster/provisioner/spawn_task.ex b/lib/spawn/cluster/provisioner/spawn_task.ex new file mode 100644 index 00000000..487725c6 --- /dev/null +++ b/lib/spawn/cluster/provisioner/spawn_task.ex @@ -0,0 +1,3 @@ +defmodule Spawn.Cluster.Provisioner.SpawnTask do + defstruct [:parent, :invocation, :opts, :state] +end