Skip to content

Commit 4dcaefa

Browse files
authored
Run diff generation in short-lived task process (#148)
LiveView processes are long-lived, so their heap memory accumulates. By running diff generation in a task under Task.Supervisor, the task's entire heap is freed immediately on exit and TmpDir cleanup triggers automatically via the :DOWN monitor.
1 parent bb53f2c commit 4dcaefa

1 file changed

Lines changed: 47 additions & 36 deletions

File tree

lib/diff_web/live/diff_live_view.ex

Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -144,44 +144,55 @@ defmodule DiffWeb.DiffLiveView do
144144
def handle_info({:generate_diff, package, from, to}, socket) do
145145
hex_impl = Application.get_env(:diff, :hex_impl, Diff.Hex)
146146

147-
try do
148-
case hex_impl.diff(package, from, to) do
149-
{:ok, stream} ->
150-
case process_stream_to_diffs(package, from, to, stream) do
151-
{:ok, metadata, diff_ids} ->
152-
initial_batch_size = 5
153-
{initial_diffs, _remaining} = Enum.split(diff_ids, initial_batch_size)
154-
155-
socket =
156-
socket
157-
|> assign(
158-
metadata: metadata,
159-
all_diff_ids: diff_ids,
160-
loaded_diffs: [],
161-
loaded_diff_content: %{},
162-
remaining_diffs: diff_ids,
163-
generating: false,
164-
has_more_diffs: length(diff_ids) > 0
165-
)
166-
167-
send(self(), {:load_diffs, initial_diffs})
168-
169-
{:noreply, socket}
170-
171-
{:error, reason} ->
172-
Logger.error("Failed to generate diff: #{inspect(reason)}")
173-
{:noreply, assign(socket, error: "Failed to generate diff", generating: false)}
174-
end
175-
176-
:error ->
177-
{:noreply, assign(socket, error: "Failed to generate diff", generating: false)}
147+
task =
148+
Task.Supervisor.async(Diff.Tasks, fn ->
149+
case hex_impl.diff(package, from, to) do
150+
{:ok, stream} ->
151+
process_stream_to_diffs(package, from, to, stream)
152+
153+
:error ->
154+
:error
155+
end
156+
end)
157+
158+
result =
159+
case Task.yield(task, :timer.seconds(60)) || Task.shutdown(task) do
160+
{:ok, result} -> result
161+
{:exit, _reason} -> :error
162+
nil -> :error
178163
end
179-
catch
180-
:throw, {:diff, :invalid_diff} ->
181-
{:noreply, assign(socket, error: "Invalid diff", generating: false)}
182-
after
183-
Diff.TmpDir.cleanup()
164+
165+
case result do
166+
{:ok, metadata, diff_ids} ->
167+
initial_batch_size = 5
168+
{initial_diffs, _remaining} = Enum.split(diff_ids, initial_batch_size)
169+
170+
socket =
171+
socket
172+
|> assign(
173+
metadata: metadata,
174+
all_diff_ids: diff_ids,
175+
loaded_diffs: [],
176+
loaded_diff_content: %{},
177+
remaining_diffs: diff_ids,
178+
generating: false,
179+
has_more_diffs: length(diff_ids) > 0
180+
)
181+
182+
send(self(), {:load_diffs, initial_diffs})
183+
184+
{:noreply, socket}
185+
186+
{:error, reason} ->
187+
Logger.error("Failed to generate diff: #{inspect(reason)}")
188+
{:noreply, assign(socket, error: "Failed to generate diff", generating: false)}
189+
190+
:error ->
191+
{:noreply, assign(socket, error: "Failed to generate diff", generating: false)}
184192
end
193+
catch
194+
:throw, {:diff, :invalid_diff} ->
195+
{:noreply, assign(socket, error: "Invalid diff", generating: false)}
185196
end
186197

187198
def handle_info({:load_diffs_and_update, diff_ids}, socket) do

0 commit comments

Comments
 (0)