Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Storage adapter implementation: Implemented Quantum.Storage.Adapter behavior via PersistentETS. #318

Closed
wants to merge 7 commits into from

Conversation

pyatkov
Copy link
Contributor

@pyatkov pyatkov commented Mar 5, 2018

Provides an implementation of the Quantum.Storage.Adapter behaviour via Persistent ETS library.
The specialty is that the behaviour is implemented as a GenServer and requires explicit starting as a worker process before the scheduler app.
The whole need for GenServer-ish behaviour appeared due to default :protected access to the ETS table (which implies only the process that created the table can have write access to it). GenServer-ish behaviour allows us to have a dedicated process to access the ETS table thus resolving this issue.
We could have considered the table to be :public, but things inclined the GenServer-ish approach.

We also don't have ane tests targeting specifically this implementation module. Still, we could probably test the functionality by configuring this storage adapter via the :storage option in the application configuration.

@pyatkov pyatkov changed the title Storage adapter implementation: Implemented Quantum.Storage.Adapter bahavior via PersistentETS. Storage adapter implementation: Implemented Quantum.Storage.Adapter behavior via PersistentETS. Mar 5, 2018
@maennchen maennchen self-requested a review March 5, 2018 13:24
@maennchen maennchen self-assigned this Mar 5, 2018
@maennchen
Copy link
Member

@pyatkov Can you do me a favor and rebase again on the branch? I had to merge in some changes from the master.

mix.exs Outdated
@@ -80,7 +80,8 @@ defmodule Quantum.Mixfile do
{:excoveralls, "~> 0.5", only: [:dev, :test], runtime: false},
{:inch_ex, "~> 0.5", only: [:dev, :docs], runtime: false},
{:dialyxir, "~> 0.5", only: [:dev, :test], runtime: false},
{:credo, "~> 0.7", only: [:dev, :test], runtime: false}
{:credo, "~> 0.7", only: [:dev, :test], runtime: false},
{:persistent_ets, "~> 0.1.0"},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make the dependency optional. Not everyone will need the storage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an observation: here and in many many places, diligent coders have to specify runtime: false as they don't need the application to start (sometimes there is no application defined in the package). Just wondering if it was really a good move to make the dependencies start as an app by default? Kind of a move towards the newcomers, but in about a week or so, they become aware of the apps and become concerned about the runtime: false options as all the others do.
For me, the old good explicit aplication start looked a more neat and manture option.

I'll do the rebase.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pyatkov I'd rather not move away from the standard in Elixir. In my professional opinion, it will be even more complicated if every other place does this differently.

Copy link

@dapdizzy dapdizzy Mar 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maennchen
As I said, it was Just an observation., so ...
BTW, this is my personal account whose repo I use for developing the PR.

@@ -0,0 +1,195 @@
defmodule Quantum.Storage.PersistentEts do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrap the defmodule in if Code.ensure_compiled?(PersistentEts) do .... end

@maennchen
Copy link
Member

@pyatkov I think we can implement a global test suite for every adapter. I'll have a look at that after the merge.

# Maybe one second elapsed in the test?
assert_receive {:received, {:execute, ^job}}, 1000

# Goes back to normal pace
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bug of my test. I'm going to fix it in the storage branch.

… storage

# Conflicts:
#	lib/quantum/job_broadcaster.ex
#	test/quantum/execution_broadcaster_test.exs
#	test/quantum/job_broadcaster_test.exs
@maennchen maennchen changed the base branch from storage to master March 7, 2018 11:21
@maennchen maennchen changed the base branch from master to storage March 7, 2018 11:21
… not Application to be started).

Made Quantum.Storage.PersistentEts module definition optional depending on whether dependent PersistentEts module is compiled and loaded.
@@ -34,8 +34,10 @@ defmodule Quantum.JobBroadcaster do

@doc false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think your merge was not clean. What changes did you make here?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I messed up a couple of times doing the rebase stuff...
I think I fixed that in the latest commit.
Still TravisCI still complains about the formatting issues.
Though when I try to do mix format a while bunch of changes pops up.
I believe I should only commit format changes to the files Travis is complaining about (there will be three of them).
I'll try do to that shortly.

@@ -153,6 +159,8 @@ defmodule Quantum.JobBroadcaster do

:ok = storage.purge(scheduler)

:ok = storage.purge(scheduler)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why purge twice?

Copy link

@dapdizzy dapdizzy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made a note about code changes in job_broadcaster.ex.

jobs: Enum.into(jobs, %{}, fn %{name: name} = job -> {name, job} end),
buffer: for(%{state: :active} = job <- jobs, do: {:add, job}),
jobs: Enum.into(effective_jobs, %{}, fn %{name: name} = job -> {name, job} end),
buffer: for(%{state: :active} = job <- effective_jobs, do: {:add, job}),
storage: storage,
scheduler: scheduler
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just realized that the existing code was rebinding the jobs variable, so...effective_jobs variable is basically not needed.
I could probably stick with the jobs variable.
I mean this part could be reverted (what existed in the master repo storage branch is just fine).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good like this 👍

@maennchen
Copy link
Member

@dapdizzy I'm going to merge into storage. Be aware that I want to make sure that everything is stable before it will be released. So it may take a few days until this will be live.

@maennchen
Copy link
Member

Thank you very much!

@maennchen
Copy link
Member

Merged manually.

@maennchen maennchen closed this Mar 7, 2018
@dapdizzy
Copy link

dapdizzy commented Mar 7, 2018 via email

@maennchen
Copy link
Member

Couldn't imagine it would be that great!

I hope it is :)

I'm aware this needs through testing, just saying.

I'm going to write a general test suite for all connectors.

Note that ':persistent_ets' dep should be included into the client app using ':quantum' explicitly, otherwise it will not be obtained

We're going to mention that in the documentation.

Would love to get my hands on developing new PRs soon!

There's a few idea tickets if you're searching for some inspiration: https://github.com/c-rack/quantum-elixir/issues?q=is%3Aissue+is%3Aopen+label%3Aidea

As soon as we have storage in stable, it would be cool if we could tackle #314. I'd really appreciate your help on it.

@c-rack
Copy link
Member

c-rack commented Mar 7, 2018

@pyatkov @dapdizzy thanks a lot for your contributions!
Are you the same person using two github accounts? 😉

@dapdizzy
Copy link

dapdizzy commented Mar 8, 2018 via email

@mertkahyaoglu
Copy link

Thank you very much for this feature. I really needed to persist runtime jobs. How can I add this to my project? Is there any documentation?

@maennchen
Copy link
Member

Sure, check this documentation page: https://hexdocs.pm/quantum/Quantum.Storage.Adapter.html#content

@mertkahyaoglu
Copy link

mertkahyaoglu commented Sep 3, 2018

@maennchen I'm trying to install quantum_storage_ets but it says;

(Mix) No package with name quantum_storage_ets (from: mix.exs) in registry.

How am I suppose to use this adapter?

@dapdizzy
Copy link

dapdizzy commented Sep 4, 2018

This particular detail seems to be missing (or located somewhere else) in the documentation.

In order to make it work, you need to do the following:
':persistent_ets' dep should be included into the client app (your app)
using ':quantum' explicitly, otherwise it will not be obtained (I believe
you are aware if this, but I faced it for the first time though).
Also 'Quantum.Storage.PersistentEts' should be started as a worker (without
args) explicitly before the Scheduler process in order to work.

I think these two things should make it work.

@mertkahyaoglu

So, the dependency name is 'persistent_ets' and a worker for a module 'Quantum.Storage.PersistentEts' without arguments (i.e. '[]') is required to be started prior to the scheduler process.

@maennchen
Copy link
Member

@mertkahyaoglu The dependency is not yet on hex. I forgot to publish it there. I‘ll do that today.

Until then you can install it via git.

@maennchen
Copy link
Member

@dapdizzy Most things about you comment above is no longer correct since it was extracted into a separate dependency.

@mertkahyaoglu
Copy link

mertkahyaoglu commented Sep 4, 2018

Most things about you comment above is no longer correct since it was extracted into a separate dependency.

@maennchen After installing the dependency, I need to add the worker to my supervisor though right? Then I can add my jobs to storage.

Sorry if I'm asking obvious questions. I'm really new to Elixir 😅 Thanks so much again for helping!

@dapdizzy
Copy link

dapdizzy commented Sep 4, 2018 via email

@mertkahyaoglu
Copy link

mertkahyaoglu commented Sep 4, 2018

I managed to store my jobs. Now I need to load them when I restarted my server. I suppose they are not being started automatically. Could you guys help me one last time please?

@maennchen
Copy link
Member

@mertkahyaoglu They should actually ve restarted automatically. Could you enable debug logging and open a new issue with that log so I can track it down?

@maennchen
Copy link
Member

@dapdizzy No worries! I just thought that I have to correct that with the extracted project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants