Skip to content

Commit d4ef34e

Browse files
committed
perf: speed up stargazer imports
1 parent be17aef commit d4ef34e

File tree

5 files changed

+96
-30
lines changed

5 files changed

+96
-30
lines changed

lib/algora/admin/admin.ex

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ defmodule Algora.Admin do
2121
alias Algora.Workspace
2222
alias Algora.Workspace.Installation
2323
alias Algora.Workspace.Jobs.FetchTopContributions
24-
alias Algora.Workspace.Jobs.ImportStargazer
24+
alias Algora.Workspace.Jobs.ProcessStargazers
2525
alias Algora.Workspace.Jobs.SyncUser
2626
alias Algora.Workspace.Repository
2727
alias Algora.Workspace.Ticket
@@ -1029,10 +1029,10 @@ defmodule Algora.Admin do
10291029
end
10301030
end
10311031

1032-
def import_stargazers(repo_url, max_pages \\ nil) when is_binary(repo_url) do
1032+
def import_stargazers(repo_url, page \\ 1, max_pages \\ nil) when is_binary(repo_url) do
10331033
with {:ok, [owner: repo_owner, repo: repo_name]} <- parse_repo_url(repo_url),
1034-
{:ok, repo} <- Workspace.ensure_repository(token(), repo_owner, repo_name) do
1035-
fetch_and_import_stargazers(repo_owner, repo_name, repo.id, 1, max_pages)
1034+
{:ok, repo} <- Workspace.ensure_repository(Github.TokenPool.get_token(), repo_owner, repo_name) do
1035+
fetch_and_import_stargazers(repo_owner, repo_name, repo.id, page, max_pages)
10361036
else
10371037
error ->
10381038
Logger.error("Failed to import stargazers: #{inspect(error)}")
@@ -1047,28 +1047,25 @@ defmodule Algora.Admin do
10471047
else
10481048
url = "/repos/#{repo_owner}/#{repo_name}/stargazers?per_page=100&page=#{page}"
10491049

1050-
case Github.Client.fetch(token(), url) do
1050+
case Github.Client.fetch(Github.TokenPool.get_token(), url) do
10511051
{:ok, []} ->
10521052
Logger.info("Finished importing stargazers - no more pages")
10531053
:ok
10541054

10551055
{:ok, stargazers} ->
1056-
stargazers
1057-
|> Enum.chunk_every(10)
1058-
|> Enum.each(fn users ->
1059-
logins = Enum.map(users, fn user -> user["login"] end)
1060-
1061-
%{provider_logins: logins, repo_id: repo_id}
1062-
|> ImportStargazer.new()
1063-
|> Oban.insert()
1064-
|> case do
1065-
{:ok, _job} -> Logger.info("Enqueued job for #{logins}")
1066-
{:error, error} -> Logger.error("Failed to enqueue job for #{logins}: #{inspect(error)}")
1067-
end
1068-
end)
1069-
1070-
# Process next page
1071-
fetch_and_import_stargazers(repo_owner, repo_name, repo_id, page + 1, max_pages)
1056+
logins = Enum.map(stargazers, fn user -> user["login"] end)
1057+
1058+
case %{provider_logins: logins, repo_id: repo_id}
1059+
|> ProcessStargazers.new()
1060+
|> Oban.insert() do
1061+
{:ok, _job} ->
1062+
Logger.info("Enqueued job for #{logins}")
1063+
fetch_and_import_stargazers(repo_owner, repo_name, repo_id, page + 1, max_pages)
1064+
1065+
{:error, error} ->
1066+
Logger.error("Failed to enqueue job for #{logins}: #{inspect(error)}")
1067+
{:error, :failed_to_enqueue_job}
1068+
end
10721069

10731070
error ->
10741071
Logger.error("Failed to fetch stargazers page #{page}: #{inspect(error)}")

lib/algora/workspace/jobs/fetch_top_contributions.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ defmodule Algora.Workspace.Jobs.FetchTopContributions do
22
@moduledoc false
33
use Oban.Worker,
44
queue: :fetch_top_contributions,
5-
max_attempts: 3
5+
max_attempts: 2,
6+
unique: [period: 30 * 24 * 60 * 60, fields: [:args]]
67

78
alias Algora.Github
89

lib/algora/workspace/jobs/import_stargazer.ex

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ defmodule Algora.Workspace.Jobs.ImportStargazer do
1111
@impl Oban.Worker
1212
def perform(%Oban.Job{args: %{"provider_logins" => provider_logins, "repo_id" => repo_id}}) do
1313
with {:ok, users} <- Algora.Workspace.fetch_top_contributions_async(Github.TokenPool.get_token(), provider_logins) do
14-
{count, _} =
14+
{_count, _} =
1515
Repo.insert_all(
1616
Stargazer,
1717
Enum.map(users, fn user ->
@@ -25,13 +25,27 @@ defmodule Algora.Workspace.Jobs.ImportStargazer do
2525
end)
2626
)
2727

28-
if count > 0 do
29-
:ok
30-
else
31-
{:error, :insert_all_failed}
32-
end
28+
:ok
3329
end
3430
end
3531

36-
def timeout(_), do: :timer.seconds(30)
32+
def perform(%Oban.Job{args: %{"provider_login" => provider_login, "repo_id" => repo_id}}) do
33+
with {:ok, users} <- Algora.Workspace.fetch_top_contributions_async(Github.TokenPool.get_token(), [provider_login]) do
34+
{_count, _} =
35+
Repo.insert_all(
36+
Stargazer,
37+
Enum.map(users, fn user ->
38+
%{
39+
id: Nanoid.generate(),
40+
inserted_at: DateTime.utc_now(),
41+
updated_at: DateTime.utc_now(),
42+
user_id: user.id,
43+
repository_id: repo_id
44+
}
45+
end)
46+
)
47+
48+
:ok
49+
end
50+
end
3751
end
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
defmodule Algora.Workspace.Jobs.ProcessStargazers do
2+
@moduledoc false
3+
use Oban.Worker,
4+
queue: :sync_contribution,
5+
max_attempts: 3
6+
7+
import Ecto.Query
8+
9+
alias Algora.Github
10+
alias Algora.Repo
11+
alias Algora.Workspace
12+
alias Algora.Workspace.Jobs.ImportStargazer
13+
alias Algora.Workspace.Stargazer
14+
15+
require Logger
16+
17+
@impl Oban.Worker
18+
def perform(%Oban.Job{args: %{"provider_logins" => provider_logins, "repo_id" => repo_id}}) do
19+
token = Github.TokenPool.get_token()
20+
21+
jobs =
22+
provider_logins
23+
|> Enum.reduce([], fn provider_login, acc ->
24+
case Workspace.ensure_user(token, provider_login) do
25+
{:ok, user} ->
26+
if user.provider_meta["followers"] < 10 do
27+
Logger.warning("User #{provider_login} has less than 10 followers")
28+
acc
29+
else
30+
if Repo.exists?(from s in Stargazer, where: s.user_id == ^user.id and s.repository_id == ^repo_id) do
31+
acc
32+
else
33+
[user.provider_login | acc]
34+
end
35+
end
36+
37+
{:error, reason} ->
38+
Logger.error("Failed to fetch user #{provider_login}: #{reason}")
39+
acc
40+
end
41+
end)
42+
|> Enum.chunk_every(10)
43+
|> Enum.map(fn logins -> ImportStargazer.new(%{provider_logins: logins, repo_id: repo_id}) end)
44+
|> Oban.insert_all()
45+
46+
case jobs do
47+
[] ->
48+
Logger.warning("No stargazers to process for #{repo_id}")
49+
50+
_ ->
51+
:ok
52+
end
53+
end
54+
end

lib/algora/workspace/jobs/sync_contribution.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ defmodule Algora.Workspace.Jobs.SyncContribution do
22
@moduledoc false
33
use Oban.Worker,
44
queue: :sync_contribution,
5-
max_attempts: 3
5+
max_attempts: 2
66

77
alias Algora.Github
88
alias Algora.Workspace

0 commit comments

Comments
 (0)