All Projects → OvermindDL1 → Task_after

OvermindDL1 / Task_after

Elixir TaskAfter library

Programming Languages

elixir
2628 projects

Labels

Projects that are alternatives of or similar to Task after

Machinery
Machinery is an asynchronous task queue/job queue based on distributed message passing.
Stars: ✭ 5,821 (+16531.43%)
Mutual labels:  task
Void
terminal-based personal organizer
Stars: ✭ 831 (+2274.29%)
Mutual labels:  task
Gantt Elastic
Gantt Chart [ javascript gantt chart, gantt component, vue gantt, vue gantt chart, responsive gantt, project manager , vue projects ]
Stars: ✭ 869 (+2382.86%)
Mutual labels:  task
Spug
开源运维平台:面向中小型企业设计的轻量级无Agent的自动化运维平台,整合了主机管理、主机批量执行、主机在线终端、文件在线上传下载、应用发布部署、在线任务计划、配置中心、监控、报警等一系列功能。
Stars: ✭ 6,810 (+19357.14%)
Mutual labels:  task
Android Next
Android Next 公共组件库
Stars: ✭ 768 (+2094.29%)
Mutual labels:  task
Inc.runtime.queue
An runtime queue use Asynchronous program
Stars: ✭ 19 (-45.71%)
Mutual labels:  task
Mask
🎭 A CLI task runner defined by a simple markdown file
Stars: ✭ 495 (+1314.29%)
Mutual labels:  task
Npm Build Boilerplate
A collection of packages that build a website using npm scripts.
Stars: ✭ 963 (+2651.43%)
Mutual labels:  task
Whattodo
A Simple Todo app design in Flutter to keep track of your task on daily basis. Its build on BLoC Pattern. You can add a project, labels, and due-date to your task also you can sort your task on the basis of project, label, and dates
Stars: ✭ 817 (+2234.29%)
Mutual labels:  task
Taskmanager
A simple、 light(only two file)、fast 、powerful 、easy to use 、easy to extend 、 Android Library To Manager your AsyncTask/Thread/CallBack Jobqueue ! 一个超级简单,易用,轻量级,快速的异步任务管理器,类似于AsyncTask,但是比AsyncTask更好用,更易控制,从此不再写Thread ! ^_^
Stars: ✭ 25 (-28.57%)
Mutual labels:  task
Node Celery
Celery client for Node.js
Stars: ✭ 648 (+1751.43%)
Mutual labels:  task
Taskr
A simple task manager app
Stars: ✭ 760 (+2071.43%)
Mutual labels:  task
Then
🎬 Tame async code with battle-tested promises
Stars: ✭ 908 (+2494.29%)
Mutual labels:  task
Vscode Todo Plus
Manage todo lists with ease. Powerful, easy to use and customizable.
Stars: ✭ 622 (+1677.14%)
Mutual labels:  task
Bake
Bake is a bash task runner
Stars: ✭ 27 (-22.86%)
Mutual labels:  task
Topydo
A powerful todo list application for the console, using the todo.txt format.
Stars: ✭ 511 (+1360%)
Mutual labels:  task
Cargo Make
Rust task runner and build tool.
Stars: ✭ 895 (+2457.14%)
Mutual labels:  task
Queuer
Queuer is a queue manager, built on top of OperationQueue and Dispatch (aka GCD).
Stars: ✭ 964 (+2654.29%)
Mutual labels:  task
Je
A distributed job execution engine for the execution of batch jobs, workflows, remediations and more.
Stars: ✭ 30 (-14.29%)
Mutual labels:  task
Fennel
A task queue library for Python and Redis
Stars: ✭ 24 (-31.43%)
Mutual labels:  task

TaskAfter

This is a library to call a function after a set delay. Usage is as simple as: TaskAfter.task_after(500, fn -> do_something_after_500_ms() end)

Installation

Install this package by adding task_after to your list of dependencies in mix.exs:

def deps do
  [
    {:task_after, "~> 1.0.0"},
  ]
end

Global installation

To use this globally without needing to add it to your own supervision tree just add this to your configuration:

config :task_after, global_name: TaskAfter

Feel free to replace the global name of TaskAfter with anything you want. If the global name is unspecified then all usage of TaskAfter must have the :name or :pid options specified.

Local Installation

To use this locally to your application or to give distinct names so you can have different schedulars then just add the TaskAfter.Worker.start_link/1 to your supervision tree as normal, such as via:

children = [
  worker(TaskAfter.Worker, [[name: MyCustomName]]),
]

Note the 2 sets of list elements. You can have a nameless worker by leaving the name option out, such as:

children = [
  worker(TaskAfter.Worker, [[]]),
]

You will have to acquire the PID some other way, such as by querying your supervisor.

Usage

The main interface point is TaskAfter.task_after/2 and TaskAfter.task_after/3 where TaskAfter.task_after/2 just calls TaskAfter.task_after/3 with an empty set of options to use the defaults.

The arguments to TaskAfter.task_after/3 are, in this order:

  1. timeout_after_ms -> integer millisecond timeout
  2. callback -> The 0-arg callback function
  3. opts -> Can be:
    • name: name | pid: pid -> Specify a non-global task handler, if unspecified that the application :global_name must be specified
    • id: id -> A unique id, if nil or unspecified then it is auto-generated
    • call_timeout: timeout -> Override the timeout on calling to the TaskAfter.Worker
    • no_return: true -> Do not return the id or error, just try to register and forget results otherwise
    • send_result: pid -> Sends the result of the task to the specified pid
    • send_result: :in_process -> Runs the task in the TaskAfter.Worker process to do internal work, do not use this

You can also cancel a task via TaskAfter.cancel_task_after/1 and TaskAfter.cancel_task_after/2 where TaskAfter.cancel_task_after/1 just defaults to having an empty opts list.

The arguments to TaskAfter.cancel_task_after/2 are, in this order:

  1. task_id -> A task id
  2. opts -> Can be:
    • name: name | pid: pid -> Specify a non-global task handler, if unspecified that the application :global_name must be specified
    • call_timeout: timeout -> Override the timeout on calling to the TaskAfter.Worker
    • no_return: true -> Do not return the id or error, just try to register and forget results otherwise
    • run_result: pid -> Sends the result of the task to the specified pid after running it as an async task while returning the Task
    • run_result: :in_process -> Runs the task in the TaskAfter.Worker process to do internal work, do not use this, returns the value directly though
    • run_result: :async -> Runs the task as an async task and dismisses the result while returning the Task
    • run_result: nil -> Default: Does not run the task now, just cancels it immediately, returns the callback function

You can change a task via TaskAfter.change_task_after/2.

The arguments to TaskAfter.change_task_after/2 are, in this order:

  1. task_id -> A task ID
  2. opts -> Can be:
  • name: name | pid: pid -> Specify a non-global task handler, if unspecified that the application :global_name must be specified
  • call_timeout: timeout -> Override the timeout on calling to the TaskAfter.Worker`
  • no_return: true -> Do not return the id or error, just try to register and forget results otherwise
  • callback: fun -> Change the callback to this function
  • timeout_after_ms: timeout -> Change the timeout to this new value
  • send_result: pid -> Sends the result of the task to the specified pid after running it as an async task
  • send_result: :in_process -> Runs the task in the TaskAfter.Worker process to do internal work, do not use this
  • send_result: :async -> Default: Runs the task as an async task and dismisses the result
  • recreate: true -> If this is passed in then callback, timeout_after_ms, and send_result must be specified to be able to recreate the task if it is already elapsed.

Note: Of course if the task has already run then changing a setting on it won't do anything unless recreate: true is passed in.

Note: When recreate: true is used then callback, timeout_after_ms, and send_result can be passed in their value wrapped in a tagged :default tuple like timeout_after_ms: {:default, 500} and it will not change the existing value if not recreating but will use the value if it is.

They can be used as in these examples/tests:

  test "TaskAfter and forget" do
    s = self()
    assert {:ok, _auto_id} = TaskAfter.task_after(500, fn -> send(s, 42) end)
    assert_receive(42, 600)
  end

  test "TaskAfter and receive" do
    assert {:ok, _auto_id} = TaskAfter.task_after(500, fn -> 42 end, send_result: self())
    assert_receive(42, 600)
  end

  test "TaskAfter with custom id" do
    assert {:ok, :my_id} = TaskAfter.task_after(500, fn -> 42 end, id: :my_id, send_result: self())
    assert_receive(42, 600)
  end

  test "TaskAfter with custom id duplicate fails" do
    assert {:ok, :dup_id} = TaskAfter.task_after(500, fn -> 42 end, id: :dup_id, send_result: self())
    assert {:error, {:duplicate_id, :dup_id}} = TaskAfter.task_after(500, fn -> 42 end, id: :dup_id, send_result: self())
    assert_receive(42, 600)
  end

  test "TaskAfter lots of tasks" do
    assert {:ok, _} = TaskAfter.task_after(400, fn -> 400 end, send_result: self())
    assert {:ok, _} = TaskAfter.task_after(200, fn -> 200 end, send_result: self())
    assert {:ok, _} = TaskAfter.task_after(500, fn -> 500 end, send_result: self())
    assert {:ok, _} = TaskAfter.task_after(100, fn -> 100 end, send_result: self())
    assert {:ok, _} = TaskAfter.task_after(300, fn -> 300 end, send_result: self())
    assert {:ok, _} = TaskAfter.task_after(600, fn -> 600 end, send_result: self())
    assert_receive(100, 150)
    assert_receive(200, 150)
    assert_receive(300, 150)
    assert_receive(400, 150)
    assert_receive(500, 150)
    assert_receive(600, 150)
  end

  test "TaskAfter non-global by name" do
    assert {:ok, pid} = TaskAfter.Worker.start_link(name: :testing_name)
    {:ok, _auto_id} = TaskAfter.task_after(500, fn -> 42 end, send_result: self(), name: :testing_name)
    assert_receive(42, 600)
    GenServer.stop(pid)
  end

  test "TaskAfter non-global by pid" do
    assert {:ok, pid} = TaskAfter.Worker.start_link()
    assert {:ok, _auto_id} = TaskAfter.task_after(500, fn -> 42 end, send_result: self(), pid: pid)
    assert_receive(42, 600)
    GenServer.stop(pid)
  end

  test "TaskAfter in process (unsafe, can freeze the task worker if the task does not return fast)" do
    assert {:ok, pid} = TaskAfter.Worker.start_link()
    s = self()
    assert {:ok, _auto_id} = TaskAfter.task_after(500, fn -> send(s, self()) end, send_result: :in_process, pid: pid)
    assert_receive(^pid, 600)
    GenServer.stop(pid)
  end

  test "TaskAfter and cancel timer, do not run the callback" do
    cb = fn -> 42 end
    assert {:ok, auto_id} = TaskAfter.task_after(500, cb)
    assert {:ok, ^cb} = TaskAfter.cancel_task_after(auto_id)
  end

  test "TaskAfter and cancel timer, but its already been run or does not exist" do
    assert {:error, {:does_not_exist, :none}} = TaskAfter.cancel_task_after(:none)
    assert {:ok, auto_id} = TaskAfter.task_after(0, fn -> 42 end, send_result: self())
    assert_receive(42, 100)
    assert {:error, {:does_not_exist, ^auto_id}} = TaskAfter.cancel_task_after(auto_id)
  end

  test "TaskAfter and cancel but also run the callback in process (unsafe again)" do
    assert {:ok, auto_id} = TaskAfter.task_after(500, fn -> 42 end)
    assert {:ok, 42} = TaskAfter.cancel_task_after(auto_id, run_result: :in_process)
  end

  test "TaskAfter and cancel but also run the callback async" do
    s = self()
    assert {:ok, auto_id} = TaskAfter.task_after(500, fn -> send(s, 42) end)
    assert {:ok, :task} = TaskAfter.cancel_task_after(auto_id, run_result: :async)
    assert_receive(42, 600)
  end

  test "TaskAfter and cancel but also run the callback async while returning result to pid" do
    s = self()
    assert {:ok, auto_id} = TaskAfter.task_after(500, fn -> 42 end)
    assert {:ok, :task} = TaskAfter.cancel_task_after(auto_id, run_result: s)
    assert_receive(42, 600)
  end

  test "TaskAfter and crash" do
    s = self()
    len = &length/1
    d = len.([])
    assert {:ok, _auto_id0} = TaskAfter.task_after(100, fn -> send(s, 21) end)
    assert {:ok, _auto_id1} = TaskAfter.task_after(250, fn -> send(s, 1/d) end)
    assert {:ok, _auto_id2} = TaskAfter.task_after(500, fn -> send(s, 42) end)
    assert_receive(42, 600)
    assert_receive(21, 1)
    assert :no_message = (receive do m -> m after 1 -> :no_message end)
  end

  test "TaskAfter and replace callback without recreate" do
    assert {:ok, auto_id} = TaskAfter.task_after(500, fn -> 1 end, send_result: self())
    assert {:ok, ^auto_id} = TaskAfter.change_task_after(auto_id, callback: fn -> 2 end)
    assert_receive(2, 600)
    assert {:error, {:does_not_exist, ^auto_id}} = TaskAfter.change_task_after(auto_id, callback: fn -> 3 end)
  end

  test "TaskAfter and replace callback and timeout with recreate" do
    assert {:ok, auto_id} = TaskAfter.task_after(500, fn -> 1 end, send_result: self())
    assert {:ok, ^auto_id} = TaskAfter.change_task_after(auto_id, recreate_if_necessary: true, timeout_after_ms: 500, send_result: self(), callback: fn -> 2 end)
    assert_receive(2, 600)
    assert {:ok, ^auto_id} = TaskAfter.change_task_after(auto_id, recreate_if_necessary: true, timeout_after_ms: 500, send_result: self(), callback: fn -> 3 end)
    assert_receive(3, 600)
  end

  test "TaskAfter and replace callback without timeout with recreate" do
    assert {:ok, auto_id} = TaskAfter.task_after(500, fn -> 1 end, send_result: self())
    assert {:ok, ^auto_id} = TaskAfter.change_task_after(auto_id, recreate_if_necessary: true, timeout_after_ms: 500, send_result: self(), callback: fn -> 2 end)
    assert_receive(2, 600)
    assert {:ok, ^auto_id} = TaskAfter.change_task_after(auto_id, recreate_if_necessary: true, timeout_after_ms: {:default, 500}, send_result: self(), callback: fn -> 3 end)
    assert_receive(3, 600)
  end

  test "TaskAfter and replace timeout without recreate" do
    assert {:ok, auto_id} = TaskAfter.task_after(200, fn -> 1 end, send_result: self())
    assert {:ok, ^auto_id} = TaskAfter.change_task_after(auto_id, timeout_after_ms: 500)
    assert :no_message = (receive do m -> m after 300 -> :no_message end)
    assert_receive(1, 600)
  end
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].