-
Notifications
You must be signed in to change notification settings - Fork 364
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
Add automatic periodic check of URLs in jobs #483
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think quantum is overkill. We don't need to add a dependency for a recurring task this simple.
We have a blog post that goes over the basic idea, it http://elixirschool.com/blog/til-send-after/ it references this bit from the GenServer docs
defmodule MyApp.Periodically do
use GenServer
def start_link(_) do
GenServer.start_link(__MODULE__, %{})
end
@impl true
def init(state) do
# Schedule work to be performed on start
schedule_work()
{:ok, state}
end
@impl true
def handle_info(:work, state) do
# Do the desired work here
# so check urls whathaveyou with the timeout
# Reschedule once more
schedule_work()
{:noreply, state}
end
defp schedule_work do
# In 2 hours
Process.send_after(self(), :work, 2 * 60 * 60 * 1000)
end
end
Thoughts?
@notactuallypagemcconnell yeah, sure, the only problem I don't like in Any ideas on that? |
@brain-geek yes I will push up a commit with an example sometime today |
@brain-geek heres an example, I just will paste here since this branch is on your fork and I'm lazy.
Code to run off
This test proves that it runs the task twice and has minimal overhead (3 milliseconds spent sleeping) but proves the premise is sound and tests it at an OTP level. I think it works well enough. We use some code similar to this (but with some more sophistication added) at work. |
79372ab
to
7240f37
Compare
@notactuallypagemcconnell Thanks for the snippet, that's a clever way to test it! Applied. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very exciting @brain-geek!
@doomspork maybe, but then we need to mark this automatic user somehow. |
Recently I found a blog post that may help with the implementation: |
865117b
to
d696410
Compare
a174b74
to
e3f4d5a
Compare
@lccezinha Thanks for the suggestion, reworked it according to your suggestion. |
e3f4d5a
to
84d328c
Compare
@doomspork Could you check out the new version? It's now creates pending changes request instead of deleting something, so it should be more reliable. 😄 |
f4b804d
to
64436d6
Compare
64436d6
to
2cd3950
Compare
def check_job(%{url: url} = job) do | ||
case HTTPoison.head(url) do | ||
{:ok, %{status_code: 404}} -> | ||
user_id = Application.get_env(:companies, :jobs_url_checker)[:user_id] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Application.get_env(:companies, :jobs_url_checker)[:user_id]
resolves to System.get_env("JOB_CHECKER_USER_ID")
in a production environment, and nil
in other environments. Would it be simpler to read from the environment variable here and omit setting user_id
in the configuration file?
user_id = System.get_env("JOB_CHECKER_USER_ID")
That has a slight potential benefit of allowing you to change the value without restarting the app, although I'm not sure if that will make a practical difference. It also simplifies the application logic a little bit. A minor downside is that a change like this splits the configuration up between the configuration file and the application code. It may also be detrimental to use the JOB_CHECKER_USER_ID
environment variable in non-production environments if that value could be non-empty, and you wanted to ensure user_id
was nil
in those environments.
Just some food for thought 😄
where: fragment("changes->>'id' = ?", ^id) | ||
|
||
Repo.all(query) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use case for this function is to determine if any pending changes exist. The place that calls this function isn't really interested in the actual list of changes. What would you think about converting this to a predicate function?
def any?(record) do
# ...
Repo.exists?(query)
end
Companies.JobChecker.check_job/1
could then simplify its conditional like this:
if PendingChanges.any?(record) do
Jobs.delete(job, %{id: user_id})
end
@@ -71,6 +71,19 @@ defmodule Companies.PendingChanges do | |||
end | |||
end | |||
|
|||
def get_pending_changes_for(record) do | |||
resource_name = struct_to_string(record) | |||
id = record.id |> to_string() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since there's only one pipe here, what would you think about using the conventional function syntax?
id = to_string(record.id)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the preferred way given the styleguide we try to follow. We may need to update our Credo (or add it) rules for some of these.
Additionally I'd likely capture the record_id
value via a match and avoid dot notation (I don't know why, I don't much care for it personally).
No description provided.