diff --git a/.formatter.exs b/.formatter.exs
index b11432d8..d2cda26e 100644
--- a/.formatter.exs
+++ b/.formatter.exs
@@ -1,3 +1,4 @@
+# Used by "mix format"
[
- inputs: [".formatter.exs", "mix.exs", "{config,lib,test}/**/*.{ex,exs}"]
+ inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml
index b9db3118..21a46e97 100644
--- a/.github/workflows/elixir.yml
+++ b/.github/workflows/elixir.yml
@@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- - uses: actions/setup-elixir@v1
+ - uses: erlef/setup-elixir@v1
with:
otp-version: 22.3
elixir-version: 1.10.3
@@ -36,7 +36,7 @@ jobs:
with:
name: deps_lock
path: mix.lock
-
+
compile_dev:
name: Compile Dev Environment
@@ -46,7 +46,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- - uses: actions/setup-elixir@v1
+ - uses: erlef/setup-elixir@v1
with:
otp-version: 22.3
elixir-version: 1.10.3
@@ -76,7 +76,7 @@ jobs:
with:
name: compile_dev
path: _build/dev/
-
+
compile_docs:
name: Compile Docs Environment
@@ -86,7 +86,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- - uses: actions/setup-elixir@v1
+ - uses: erlef/setup-elixir@v1
with:
otp-version: 22.3
elixir-version: 1.10.3
@@ -116,7 +116,7 @@ jobs:
with:
name: compile_docs
path: _build/docs/
-
+
compile_test:
name: Compile Test Environment (OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}})
@@ -132,7 +132,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- - uses: actions/setup-elixir@v1
+ - uses: erlef/setup-elixir@v1
with:
otp-version: ${{matrix.otp}}
elixir-version: ${{matrix.elixir}}
@@ -162,7 +162,7 @@ jobs:
with:
name: compile_test-${{matrix.otp}}-${{matrix.elixir}}
path: _build/test/
-
+
compile_prod:
name: Compile Prod Environment
@@ -172,7 +172,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- - uses: actions/setup-elixir@v1
+ - uses: erlef/setup-elixir@v1
with:
otp-version: 22.3
elixir-version: 1.10.3
@@ -205,14 +205,14 @@ jobs:
format:
name: Check Formatting
-
+
runs-on: ubuntu-latest
needs: ['deps']
steps:
- uses: actions/checkout@v2
- - uses: actions/setup-elixir@v1
+ - uses: erlef/setup-elixir@v1
with:
otp-version: 22.3
elixir-version: 1.10.3
@@ -243,7 +243,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- - uses: actions/setup-elixir@v1
+ - uses: erlef/setup-elixir@v1
with:
otp-version: ${{matrix.otp}}
elixir-version: ${{matrix.elixir}}
@@ -272,7 +272,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- - uses: actions/setup-elixir@v1
+ - uses: erlef/setup-elixir@v1
with:
otp-version: 22.3
elixir-version: 1.10.3
@@ -301,7 +301,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- - uses: actions/setup-elixir@v1
+ - uses: erlef/setup-elixir@v1
with:
otp-version: 22.3
elixir-version: 1.10.3
@@ -342,7 +342,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- - uses: actions/setup-elixir@v1
+ - uses: erlef/setup-elixir@v1
with:
otp-version: 22.3
elixir-version: 1.10.3
@@ -375,7 +375,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- - uses: actions/setup-elixir@v1
+ - uses: erlef/setup-elixir@v1
with:
otp-version: 22.3
elixir-version: 1.10.3
@@ -397,4 +397,4 @@ jobs:
- uses: actions/upload-artifact@v1
with:
name: docs
- path: doc
\ No newline at end of file
+ path: doc
diff --git a/.gitignore b/.gitignore
index f5762b88..08946195 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,31 @@
-/_build
-/deps
-/doc
-/docs
+# The directory Mix will write compiled artifacts to.
+/_build/
+
+# If you run "mix test --cover", coverage assets end up here.
+/cover/
+
+# The directory Mix downloads your dependencies sources to.
+/deps/
+
+# Where third-party dependencies like ExDoc output generated docs.
+/doc/
+
+# Ignore .fetch files in case you like to edit your project deps locally.
+/.fetch
+
+# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
-mix.lock
+
+# Also ignore archive artifacts (built via "mix archive.build").
*.ez
-/cover
+
+# Ignore package tarball (built via "mix hex.build").
+quantum-*.tar
+
+# Temporary files for e.g. tests.
+/tmp/
+
+# Misc.
+mix.lock
/priv/plts/*.plt
-/priv/plts/*.plt.hash
\ No newline at end of file
+/priv/plts/*.plt.hash
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fb0ba0d5..c0b152a4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,18 @@ This project adheres to [Semantic Versioning](http://semver.org/).
Diff for [unreleased]
+## 3.4.0 - 2021-08-10
+
+### Added
+- `telemetry` `v1.0.0` support (#483)
+- Logger Metadata (#462 & #464)
+- Support setting job `state` in config (#463)
+
+### Fixed
+- Invalid Timezone fix in `ExecutionBroadcaster` (#468)
+
+Diff for [3.4.0]
+
## 3.3.0 - 2020-09-25
### Added
@@ -68,7 +80,7 @@ Diff for [3.0.0-rc.2]
## 3.0.0-rc.1 - 2020-02-26
-## Changed
+### Changed
- A lot of function that were not for public use have been undocumented. Those are now considered internal and may break at any point in time.
- `Quantum.Scheduler` has been renamed to `Quantum`
@@ -618,7 +630,8 @@ Diff for [1.0.0]
### Added
- Initial commit
-[unreleased]: https://github.com/quantum-elixir/quantum-core/compare/v3.3.0...HEAD
+[unreleased]: https://github.com/quantum-elixir/quantum-core/compare/v3.4.0...HEAD
+[3.3.0]: https://github.com/quantum-elixir/quantum-core/compare/v3.3.0...v3.4.0
[3.3.0]: https://github.com/quantum-elixir/quantum-core/compare/v3.2.0...v3.3.0
[3.2.0]: https://github.com/quantum-elixir/quantum-core/compare/v3.1.0...v3.2.0
[3.1.0]: https://github.com/quantum-elixir/quantum-core/compare/v3.0.2...v3.1.0
diff --git a/README.md b/README.md
index 16707821..11072a6c 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,29 @@
# Quantum
-[Cron](https://en.wikipedia.org/wiki/Cron)-like job scheduler for [Elixir](http://elixir-lang.org/).
-
-[](https://opencollective.com/quantum) [](https://hex.pm/packages/quantum)
-[](https://hexdocs.pm/quantum)
-
+[](https://opencollective.com/quantum)
+[](https://github.com/quantum-elixir/quantum-core/actions/workflows/elixir.yml)
[](https://coveralls.io/r/quantum-elixir/quantum-core?branch=master)
-[](https://hex.pm/packages/quantum)
+[](https://hex.pm/packages/quantum)
+[](https://hexdocs.pm/quantum/)
+[](https://hex.pm/packages/quantum)
+[](https://github.com/quantum-elixir/quantum-core/blob/master/LICENSE)
+[](https://github.com/quantum-elixir/quantum-core/commits/master)
> **This README follows master, which may not be the currently published version**. Here are the
[docs for the latest published version of Quantum](https://hexdocs.pm/quantum/readme.html).
+[Cron](https://en.wikipedia.org/wiki/Cron)-like job scheduler for [Elixir](http://elixir-lang.org/).
+
## Setup
-To use Quantum in your project, edit the `mix.exs` file and add Quantum to
+To use Quantum in your project, edit the `mix.exs` file and add `Quantum` to
**1. the list of dependencies:**
```elixir
defp deps do
- [{:quantum, "~> 3.0"}]
+ [
+ {:quantum, "~> 3.0"}
+ ]
end
```
@@ -35,8 +40,6 @@ defmodule Acme.Application do
use Application
def start(_type, _args) do
- import Supervisor.Spec, warn: false
-
children = [
# This is the new line
Acme.Scheduler
@@ -92,10 +95,9 @@ More details on the usage can be found in the [Documentation](https://hexdocs.pm
This project uses the [Collective Code Construction Contract (C4)](http://rfc.zeromq.org/spec:42/C4/) for all code changes.
-> "Everyone, without distinction or discrimination, SHALL have an equal right to become a Contributor under the
-terms of this contract."
+> "Everyone, without distinction or discrimination, SHALL have an equal right to become a Contributor under the terms of this contract."
-### tl;dr
+### TL;DR
1. Check for [open issues](https://github.com/quantum-elixir/quantum-core/issues) or [open a new issue](https://github.com/quantum-elixir/quantum-core/issues/new) to start a discussion around [a problem](https://www.youtube.com/watch?v=_QF9sFJGJuc).
2. Issues SHALL be named as "Problem: _description of the problem_".
@@ -108,7 +110,8 @@ terms of this contract."
### Code Contributors
This project exists thanks to all the people who contribute.
-
+
+[](https://github.com/quantum-elixir/quantum-core/graphs/contributors)
### Financial Contributors
@@ -116,23 +119,33 @@ Become a financial contributor and help us sustain our community. [[Contribute](
#### Individuals
-
+[](https://opencollective.com/quantum)
#### Organizations
Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/quantum/contribute)]
-
-
-
-
-
-
-
-
-
-
-
-## License
-
-[Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
+[](https://opencollective.com/quantum/organization/0/website)
+[](https://opencollective.com/quantum/organization/1/website)
+[](https://opencollective.com/quantum/organization/2/website)
+[](https://opencollective.com/quantum/organization/3/website)
+[](https://opencollective.com/quantum/organization/4/website)
+[](https://opencollective.com/quantum/organization/5/website)
+[](https://opencollective.com/quantum/organization/6/website)
+[](https://opencollective.com/quantum/organization/7/website)
+[](https://opencollective.com/quantum/organization/8/website)
+[](https://opencollective.com/quantum/organization/9/website)
+
+## Copyright and License
+
+Copyright (c) 2015 Constantin Rack
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/assets/quantum-elixir-logo.svg b/assets/quantum-elixir-logo.svg
new file mode 100644
index 00000000..8e659297
--- /dev/null
+++ b/assets/quantum-elixir-logo.svg
@@ -0,0 +1,12 @@
+
+
+
diff --git a/config/config.exs b/config/config.exs
index ae722aea..895be551 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -1,2 +1,3 @@
use Mix.Config
+config :logger, :console, metadata: [:all, :crash_reason]
config :elixir, :time_zone_database, Tzdata.TimeZoneDatabase
diff --git a/lib/quantum/clock_broadcaster.ex b/lib/quantum/clock_broadcaster.ex
index 0d2631f7..d84e134f 100644
--- a/lib/quantum/clock_broadcaster.ex
+++ b/lib/quantum/clock_broadcaster.ex
@@ -107,17 +107,18 @@ defmodule Quantum.ClockBroadcaster do
new_remaining_demand = remaining_demand - Enum.count(events)
if remaining_demand > 0 and new_remaining_demand == 0 do
- log_catched_up(state)
+ log_caught_up(state)
end
{:noreply, events, %State{state | time: new_time, remaining_demand: new_remaining_demand}}
end
- defp log_catched_up(%State{debug_logging: false}), do: :ok
+ defp log_caught_up(%State{debug_logging: false}), do: :ok
- defp log_catched_up(%State{debug_logging: true}),
+ defp log_caught_up(%State{debug_logging: true}),
do:
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Clock Producer catched up with past times and is now running in normal time"
+ {"Clock Producer caught up with past times and is now running in normal time",
+ node: Node.self()}
end)
end
diff --git a/lib/quantum/execution_broadcaster.ex b/lib/quantum/execution_broadcaster.ex
index 5a0ea10b..b64b0789 100644
--- a/lib/quantum/execution_broadcaster.ex
+++ b/lib/quantum/execution_broadcaster.ex
@@ -101,9 +101,7 @@ defmodule Quantum.ExecutionBroadcaster do
) do
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Scheduling job for single reboot execution: #{
- inspect(name)
- }"
+ {"Scheduling job for single reboot execution", node: Node.self(), name: name}
end)
{[%ExecuteEvent{job: job}], %{state | uninitialized_jobs: [job | uninitialized_jobs]}}
@@ -115,7 +113,7 @@ defmodule Quantum.ExecutionBroadcaster do
) do
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Adding job #{inspect(name)}"
+ {"Adding job", node: Node.self(), name: name}
end)
{[], %{state | uninitialized_jobs: [job | uninitialized_jobs]}}
@@ -127,7 +125,7 @@ defmodule Quantum.ExecutionBroadcaster do
) do
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Running job #{inspect(name)} once"
+ {"Running job once", node: Node.self(), name: name}
end)
{[%ExecuteEvent{job: job}], state}
@@ -143,7 +141,7 @@ defmodule Quantum.ExecutionBroadcaster do
) do
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Removing job #{inspect(name)}"
+ {"Removing job", node: Node.self(), name: name}
end)
uninitialized_jobs = Enum.reject(uninitialized_jobs, &(&1.name == name))
@@ -218,9 +216,7 @@ defmodule Quantum.ExecutionBroadcaster do
for %Job{name: job_name} = job <- jobs do
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Scheduling job for execution #{
- inspect(job_name)
- }"
+ {"Scheduling job for execution", node: Node.self(), name: job_name}
end)
%ExecuteEvent{job: job}
@@ -267,6 +263,8 @@ defmodule Quantum.ExecutionBroadcaster do
job: job,
error: e
)
+
+ state
end
defp get_next_execution_time(
diff --git a/lib/quantum/executor.ex b/lib/quantum/executor.ex
index 59bdd9e0..de435cea 100644
--- a/lib/quantum/executor.ex
+++ b/lib/quantum/executor.ex
@@ -51,7 +51,7 @@ defmodule Quantum.Executor do
) do
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Start execution of job #{inspect(job_name)}"
+ {"Start execution of job", node: Node.self(), name: job_name}
end)
case TaskRegistry.mark_running(task_registry, job_name, node) do
@@ -84,63 +84,37 @@ defmodule Quantum.Executor do
) do
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Task for job #{inspect(job_name)} started on node #{
- node
- }"
+ {"Task for job started on node", node: Node.self(), name: job_name, started_on: node}
end)
Task.Supervisor.async_nolink({task_supervisor, node}, fn ->
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Execute started for job #{inspect(job_name)}"
+ {"Execute started for job", node: Node.self(), name: job_name}
end)
- # Note: we are intentionally mimicking the ":telemetry.span" here to keep current functionality
- start_monotonic_time = :erlang.monotonic_time()
-
- :telemetry.execute([:quantum, :job, :start], %{system_time: start_monotonic_time}, %{
- job: job,
- node: node,
- scheduler: scheduler
- })
-
try do
- execute_task(task)
+ :telemetry.span([:quantum, :job], %{job: job, node: node, scheduler: scheduler}, fn ->
+ result = execute_task(task)
+ {result, %{job: job, node: node, scheduler: scheduler, result: result}}
+ end)
catch
type, value ->
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Execution ended for job #{
- inspect(job_name)
- }, which failed due to: #{Exception.format(type, value, __STACKTRACE__)}"
+ {
+ "Execution failed for job",
+ node: Node.self(), name: job_name, type: type, value: value
+ }
end)
- duration = :erlang.monotonic_time() - start_monotonic_time
-
- :telemetry.execute([:quantum, :job, :exception], %{duration: duration}, %{
- job: job,
- node: node,
- reason: value,
- stacktrace: __STACKTRACE__,
- scheduler: scheduler
- })
+ log_exception(type, value, __STACKTRACE__)
else
result ->
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Execution ended for job #{
- inspect(job_name)
- }, which yielded result: #{inspect(result)}"
+ {"Execution ended for job", node: Node.self(), name: job_name, result: result}
end)
-
- duration = :erlang.monotonic_time() - start_monotonic_time
-
- :telemetry.execute([:quantum, :job, :stop], %{duration: duration}, %{
- job: job,
- node: node,
- scheduler: scheduler,
- result: result
- })
end
:ok
@@ -156,4 +130,24 @@ defmodule Quantum.Executor do
defp execute_task(fun) when is_function(fun, 0) do
fun.()
end
+
+ def log_exception(kind, reason, stacktrace) do
+ reason = Exception.normalize(kind, reason, stacktrace)
+
+ # TODO: Remove in a future version and make elixir 1.10 minimum requirement
+ if Version.match?(System.version(), "< 1.10.0") do
+ Logger.error(Exception.format(kind, reason, stacktrace))
+ else
+ crash_reason =
+ case kind do
+ :throw -> {{:nocatch, reason}, stacktrace}
+ _ -> {reason, stacktrace}
+ end
+
+ Logger.error(
+ Exception.format(kind, reason, stacktrace),
+ crash_reason: crash_reason
+ )
+ end
+ end
end
diff --git a/lib/quantum/job_broadcaster.ex b/lib/quantum/job_broadcaster.ex
index 03a8812f..608bd76c 100644
--- a/lib/quantum/job_broadcaster.ex
+++ b/lib/quantum/job_broadcaster.ex
@@ -49,7 +49,7 @@ defmodule Quantum.JobBroadcaster do
:not_applicable ->
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Loading Initial Jobs from Config"
+ {"Loading Initial Jobs from Config", node: Node.self()}
end)
jobs
@@ -57,7 +57,7 @@ defmodule Quantum.JobBroadcaster do
storage_jobs when is_list(storage_jobs) ->
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Loading Initial Jobs from Storage, skipping config"
+ {"Loading Initial Jobs from Storage, skipping config", node: Node.self()}
end)
for %Job{state: :active} = job <- storage_jobs do
@@ -104,17 +104,10 @@ defmodule Quantum.JobBroadcaster do
%{^job_name => %Job{state: :active} = old_job} ->
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Replacing job #{inspect(job_name)}"
+ {"Replacing job", node: Node.self(), name: job_name}
end)
- # Send event to telemetry incase the end user wants to monitor events
- :telemetry.execute([:quantum, :job, :update], %{}, %{
- job: job,
- scheduler: state.scheduler
- })
-
- :ok = storage.delete_job(storage_pid, job_name)
- :ok = storage.add_job(storage_pid, job)
+ :ok = update_job(storage, storage_pid, job, state.scheduler)
{:noreply, [{:delete, old_job}, {:add, job}],
%{state | jobs: Map.put(jobs, job_name, job)}}
@@ -122,24 +115,17 @@ defmodule Quantum.JobBroadcaster do
%{^job_name => %Job{state: :inactive}} ->
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Replacing job #{inspect(job_name)}"
+ {"Replacing job", node: Node.self(), name: job_name}
end)
- # Send event to telemetry incase the end user wants to monitor events
- :telemetry.execute([:quantum, :job, :update], %{}, %{
- job: job,
- scheduler: state.scheduler
- })
-
- :ok = storage.delete_job(storage_pid, job_name)
- :ok = storage.add_job(storage_pid, job)
+ :ok = update_job(storage, storage_pid, job, state.scheduler)
{:noreply, [{:add, job}], %{state | jobs: Map.put(jobs, job_name, job)}}
_ ->
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Adding job #{inspect(job_name)}"
+ {"Adding job", node: Node.self(), name: job_name}
end)
# Send event to telemetry incase the end user wants to monitor events
@@ -167,41 +153,27 @@ defmodule Quantum.JobBroadcaster do
%{^job_name => %Job{state: :active} = old_job} ->
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Replacing job #{inspect(job_name)}"
+ {"Replacing job", node: Node.self(), name: job_name}
end)
- # Send event to telemetry incase the end user wants to monitor events
- :telemetry.execute([:quantum, :job, :update], %{}, %{
- job: job,
- scheduler: state.scheduler
- })
-
- :ok = storage.delete_job(storage_pid, job_name)
- :ok = storage.add_job(storage_pid, job)
+ :ok = update_job(storage, storage_pid, job, state.scheduler)
{:noreply, [{:delete, old_job}], %{state | jobs: Map.put(jobs, job_name, job)}}
%{^job_name => %Job{state: :inactive}} ->
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Replacing job #{inspect(job_name)}"
+ {"Replacing job", node: Node.self(), name: job_name}
end)
- # Send event to telemetry incase the end user wants to monitor events
- :telemetry.execute([:quantum, :job, :update], %{}, %{
- job: job,
- scheduler: state.scheduler
- })
-
- :ok = storage.delete_job(storage_pid, job_name)
- :ok = storage.add_job(storage_pid, job)
+ :ok = update_job(storage, storage_pid, job, state.scheduler)
{:noreply, [], %{state | jobs: Map.put(jobs, job_name, job)}}
_ ->
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Adding job #{inspect(job_name)}"
+ {"Adding job", node: Node.self(), name: job_name}
end)
# Send event to telemetry incase the end user wants to monitor events
@@ -227,7 +199,7 @@ defmodule Quantum.JobBroadcaster do
) do
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Deleting job #{inspect(name)}"
+ {"Deleting job", node: Node.self(), name: name}
end)
case Map.fetch(jobs, name) do
@@ -269,7 +241,7 @@ defmodule Quantum.JobBroadcaster do
) do
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Change job state #{inspect(name)}"
+ {"Change job state", node: Node.self(), name: name}
end)
case Map.fetch(jobs, name) do
@@ -309,7 +281,7 @@ defmodule Quantum.JobBroadcaster do
) do
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Running job #{inspect(name)} once"
+ {"Running job once", node: Node.self(), name: name}
end)
case Map.fetch(jobs, name) do
@@ -332,7 +304,7 @@ defmodule Quantum.JobBroadcaster do
) do
debug_logging &&
Logger.debug(fn ->
- "[#{inspect(Node.self())}][#{__MODULE__}] Deleting all jobs"
+ {"Deleting all jobs", node: Node.self()}
end)
for {_name, %Job{} = job} <- jobs do
@@ -361,4 +333,19 @@ defmodule Quantum.JobBroadcaster do
def handle_info(_message, state) do
{:noreply, [], state}
end
+
+ defp update_job(storage, storage_pid, %Job{name: job_name} = job, scheduler) do
+ # Send event to telemetry incase the end user wants to monitor events
+ :telemetry.execute([:quantum, :job, :update], %{}, %{
+ job: job,
+ scheduler: scheduler
+ })
+
+ if function_exported?(storage, :update_job, 2) do
+ :ok = storage.update_job(storage_pid, job)
+ else
+ :ok = storage.delete_job(storage_pid, job_name)
+ :ok = storage.add_job(storage_pid, job)
+ end
+ end
end
diff --git a/lib/quantum/normalizer.ex b/lib/quantum/normalizer.ex
index ceb8814d..4afc18e1 100644
--- a/lib/quantum/normalizer.ex
+++ b/lib/quantum/normalizer.ex
@@ -85,6 +85,10 @@ defmodule Quantum.Normalizer do
Job.set_timezone(job, normalize_timezone(timezone))
end
+ defp normalize_job_option({:state, state}, job) do
+ Job.set_state(job, state)
+ end
+
defp normalize_job_option(_, job), do: job
@spec normalize_task(config_task) :: Job.task() | no_return
diff --git a/lib/quantum/run_strategy/all.ex b/lib/quantum/run_strategy/all.ex
index 3de4edef..f0be096e 100644
--- a/lib/quantum/run_strategy/all.ex
+++ b/lib/quantum/run_strategy/all.ex
@@ -1,6 +1,6 @@
defmodule Quantum.RunStrategy.All do
@moduledoc """
- Run job on all node of the node list
+ Run job on all node of the node list.
If the node list is `:cluster`, all nodes of the cluster will be used.
diff --git a/lib/quantum/storage.ex b/lib/quantum/storage.ex
index a55dac5f..f88e9af9 100644
--- a/lib/quantum/storage.ex
+++ b/lib/quantum/storage.ex
@@ -1,6 +1,6 @@
defmodule Quantum.Storage do
@moduledoc """
- Bahaviour to be implemented by all Storage Adapters.
+ Behaviour to be implemented by all Storage Adapters.
The calls to the storage are blocking, make sure they're fast to not block the job execution.
"""
@@ -76,4 +76,14 @@ defmodule Quantum.Storage do
Purge all date from storage and go back to initial state.
"""
@callback purge(storage_pid :: storage_pid) :: :ok
+
+ @doc """
+ Updates existing job in storage.
+
+ This callback is optional. If not implemented then the `c:delete_job/2`
+ and then the `c:add_job/2` callbacks will be called instead.
+ """
+ @callback update_job(storage_pid :: storage_pid, job :: Job.t()) :: :ok
+
+ @optional_callbacks update_job: 2
end
diff --git a/lib/quantum/supervisor.ex b/lib/quantum/supervisor.ex
index 0468d2f4..eb2a315a 100644
--- a/lib/quantum/supervisor.ex
+++ b/lib/quantum/supervisor.ex
@@ -3,8 +3,6 @@ defmodule Quantum.Supervisor do
use Supervisor
- require Logger
-
# Starts the quantum supervisor.
@spec start_link(GenServer.server(), Keyword.t()) :: GenServer.on_start()
def start_link(quantum, opts) do
diff --git a/lib/quantum/task_registry.ex b/lib/quantum/task_registry.ex
index 6826d41b..e9b1124c 100644
--- a/lib/quantum/task_registry.ex
+++ b/lib/quantum/task_registry.ex
@@ -3,8 +3,6 @@ defmodule Quantum.TaskRegistry do
# Registry to check if a task is already running on a node.
- require Logger
-
alias __MODULE__.StartOpts
alias Quantum.Job
diff --git a/mix.exs b/mix.exs
index c5e431b7..93445556 100644
--- a/mix.exs
+++ b/mix.exs
@@ -3,7 +3,8 @@ defmodule Quantum.Mixfile do
use Mix.Project
- @version "3.3.0"
+ @source_url "https://github.com/quantum-elixir/quantum-core"
+ @version "3.4.0"
def project do
[
@@ -54,10 +55,10 @@ defmodule Quantum.Mixfile do
"Jonatan Männchen"
],
exclude_patterns: [~r[priv/plts]],
- licenses: ["Apache License 2.0"],
+ licenses: ["Apache-2.0"],
links: %{
- "Changelog" => "https://github.com/quantum-elixir/quantum-core/blob/master/CHANGELOG.md",
- "GitHub" => "https://github.com/quantum-elixir/quantum-core"
+ "Changelog" => "#{@source_url}/blob/master/CHANGELOG.md",
+ "GitHub" => @source_url
}
}
end
@@ -66,13 +67,14 @@ defmodule Quantum.Mixfile do
[
main: "readme",
source_ref: "v#{@version}",
- source_url: "https://github.com/quantum-elixir/quantum-core",
+ source_url: @source_url,
+ logo: "assets/quantum-elixir-logo.svg",
extras: [
- "README.md",
"CHANGELOG.md",
+ "README.md",
"pages/supervision-tree.md",
"pages/configuration.md",
- "pages/runtime.md",
+ "pages/runtime-configuration.md",
"pages/crontab-format.md",
"pages/run-strategies.md",
"pages/telemetry.md"
@@ -97,13 +99,12 @@ defmodule Quantum.Mixfile do
[
{:crontab, "~> 1.1"},
{:gen_stage, "~> 0.14 or ~> 1.0"},
+ {:telemetry, "~> 0.4.3 or ~> 1.0.0"},
{:tzdata, "~> 1.0", only: [:dev, :test]},
- {:earmark, "~> 1.0", only: [:dev, :docs], runtime: false},
- {:ex_doc, "~> 0.19", only: [:dev, :docs], runtime: false},
+ {:ex_doc, ">= 0.0.0", only: [:dev, :docs], runtime: false},
{:excoveralls, "~> 0.5", only: [:test], runtime: false},
{:dialyxir, "~> 1.0-rc", only: [:dev], runtime: false},
- {:credo, "~> 1.0", only: [:dev], runtime: false},
- {:telemetry, "~> 0.4"}
+ {:credo, "~> 1.0", only: [:dev], runtime: false}
]
end
end
diff --git a/pages/configuration.md b/pages/configuration.md
index 3e683c57..26e1162a 100644
--- a/pages/configuration.md
+++ b/pages/configuration.md
@@ -15,7 +15,7 @@ config :your_app, YourApp.Scheduler,
# Runs on 18, 20, 22, 0, 2, 4, 6:
{"0 18-6/2 * * *", fn -> :mnesia.backup('/var/backup/mnesia') end},
# Runs every midnight:
- {"@daily", {Backup, :backup, []}}
+ {"@daily", {Backup, :backup, []}, state: :inactive}
]
```
@@ -72,6 +72,7 @@ Possible options:
- `task` function to be performed, ex: `{Heartbeat, :send, []}` or `fn -> :something end`
- `run_strategy` strategy on how to run tasks inside of cluster, default: `%Quantum.RunStrategy.Random{nodes: :cluster}`
- `overlap` set to false to prevent next job from being executed if previous job is still running, default: `true`
+- `state` set to `:inactive` to deactivate a job or `:active` to activate it
It is possible to control the behavior of jobs at runtime.
@@ -154,6 +155,3 @@ Timezones can also be configured on a per-job basis. This overrides the default
timezone: "America/New_York"
}
```
-
-## Telemetry Support
-
diff --git a/pages/crontab-format.md b/pages/crontab-format.md
index 4bc16da5..54893a62 100644
--- a/pages/crontab-format.md
+++ b/pages/crontab-format.md
@@ -11,7 +11,7 @@
| month | 1-12 (or names) |
| day of week | 0-6 (0 is Sunday, or use abbreviated names) |
-The `second` field can only be used in extended cron expressions.
+The `second` field can only be used in extended Cron expressions.
Names can also be used for the `month` and `day of week` fields.
Use the first three letters of the particular day or month (case does not matter).
@@ -43,5 +43,5 @@ Instead of the first five fields, one of these special strings may be used:
All Cron Expressions are parsed and evaluated by [crontab](https://hex.pm/packages/crontab).
-Issues with parsing a cron expression can be reported here:
+Issues with parsing a Cron expression can be reported here:
[crontab GitHub issues](https://github.com/jshmrtn/crontab/issues)
diff --git a/pages/runtime.md b/pages/runtime-configuration.md
similarity index 100%
rename from pages/runtime.md
rename to pages/runtime-configuration.md
diff --git a/pages/supervision-tree.md b/pages/supervision-tree.md
index 0f8e0ba6..40be512c 100644
--- a/pages/supervision-tree.md
+++ b/pages/supervision-tree.md
@@ -6,10 +6,10 @@
* `YourApp.Scheduler.JobBroadcaster` (`Quantum.JobBroadcaster`) - The `GenStage` that keeps track of all jobs.
* `YourApp.Scheduler.ExecutionBroadcaster` (`Quantum.ExecutionBroadcaster`) - The `GenStage` that notifies execution of jobs.
* `YourApp.Scheduler.ExecutorSupervisor` (`Quantum.ExecutorSupervisor`) - The `ConsumerSupervisor` that spawns an Executor for every execution.
- - `no_name` (`YourApp.Scheduler.Executor`) - The `Task` that calls the `YourApp.Scheduler.Task.Supervisor` with the execution of the cron (per Node).
- * `YourApp.Scheduler.Task.Supervisor` (`Task.Supervisor`) - The `Task.Supervisor` where all cron jobs run in.
- - `Task` - The place where the defined cron job action gets called.
+ - `no_name` (`YourApp.Scheduler.Executor`) - The `Task` that calls the `YourApp.Scheduler.Task.Supervisor` with the execution of the Cron (per Node).
+ * `YourApp.Scheduler.Task.Supervisor` (`Task.Supervisor`) - The `Task.Supervisor` where all Cron jobs run in.
+ - `Task` - The place where the defined Cron job action gets called.
## Error Handling
-The OTP Supervision Tree is initiated by the user of the library. Therefore the error handling can be implemented via normal OTP means. See `Supervisor.Spec` for more information.
+The OTP Supervision Tree is initiated by the user of the library. Therefore the error handling can be implemented via normal OTP means. See `Supervisor` module for more information.
diff --git a/pages/telemetry.md b/pages/telemetry.md
index 818b4b3c..6dac35e8 100644
--- a/pages/telemetry.md
+++ b/pages/telemetry.md
@@ -1,6 +1,6 @@
# Telemetry
-Sice version [`3.2.0`](https://github.com/quantum-elixir/quantum-core/releases/tag/v3.2.0) `quantum` supports [`:telemetry`](https://hexdocs.pm/telemetry) metrics.
+Since version [`3.2.0`](https://github.com/quantum-elixir/quantum-core/releases/tag/v3.2.0) `quantum` supports [`:telemetry`](https://hexdocs.pm/telemetry) metrics.