Add parallel export with configurable concurrency (default: 8)
Use Task.async_stream for parallel org->md export. Configurable via EXPORT_CONCURRENCY env var or :export_concurrency config.
This commit is contained in:
9040
.agent-shell/transcripts/2026-02-21-14-47-23.md
Normal file
9040
.agent-shell/transcripts/2026-02-21-14-47-23.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,8 @@ config :org_garden,
|
|||||||
citation_mode: :warn,
|
citation_mode: :warn,
|
||||||
http_port: 8080,
|
http_port: 8080,
|
||||||
ws_port: 3001,
|
ws_port: 3001,
|
||||||
health_port: 9090
|
health_port: 9090,
|
||||||
|
export_concurrency: 8
|
||||||
|
|
||||||
config :logger, :console,
|
config :logger, :console,
|
||||||
format: "$time $metadata[$level] $message\n",
|
format: "$time $metadata[$level] $message\n",
|
||||||
|
|||||||
@@ -40,3 +40,7 @@ config :org_garden,
|
|||||||
http_port: RuntimeConfig.parse_int(System.get_env("PORT"), 8080),
|
http_port: RuntimeConfig.parse_int(System.get_env("PORT"), 8080),
|
||||||
ws_port: RuntimeConfig.parse_int(System.get_env("WS_PORT"), 3001),
|
ws_port: RuntimeConfig.parse_int(System.get_env("WS_PORT"), 3001),
|
||||||
health_port: RuntimeConfig.parse_int(System.get_env("HEALTH_PORT"), 9090)
|
health_port: RuntimeConfig.parse_int(System.get_env("HEALTH_PORT"), 9090)
|
||||||
|
|
||||||
|
# Export parallelism
|
||||||
|
config :org_garden,
|
||||||
|
export_concurrency: RuntimeConfig.parse_int(System.get_env("EXPORT_CONCURRENCY"), 8)
|
||||||
|
|||||||
@@ -71,9 +71,15 @@ defmodule OrgGarden.Export do
|
|||||||
e -> {:error, e}
|
e -> {:error, e}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@default_max_concurrency 8
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Export all `.org` files found under `notes_dir`.
|
Export all `.org` files found under `notes_dir`.
|
||||||
|
|
||||||
|
Exports files in parallel for improved performance. The concurrency level
|
||||||
|
can be configured via the `:export_concurrency` application config or
|
||||||
|
the `EXPORT_CONCURRENCY` environment variable. Defaults to #{@default_max_concurrency}.
|
||||||
|
|
||||||
Returns `{:ok, count}` where `count` is the number of successfully
|
Returns `{:ok, count}` where `count` is the number of successfully
|
||||||
exported files, or `{:error, failures}` if any files failed.
|
exported files, or `{:error, failures}` if any files failed.
|
||||||
"""
|
"""
|
||||||
@@ -87,13 +93,21 @@ defmodule OrgGarden.Export do
|
|||||||
Logger.warning("No .org files found in #{notes_dir}")
|
Logger.warning("No .org files found in #{notes_dir}")
|
||||||
{:ok, 0}
|
{:ok, 0}
|
||||||
else
|
else
|
||||||
Logger.info("Exporting #{length(org_files)} org file(s) from #{notes_dir}")
|
max_concurrency = get_concurrency()
|
||||||
|
Logger.info("Exporting #{length(org_files)} org file(s) from #{notes_dir} (concurrency: #{max_concurrency})")
|
||||||
|
|
||||||
results =
|
results =
|
||||||
Enum.map(org_files, fn orgfile ->
|
org_files
|
||||||
IO.puts(" exporting: #{orgfile}")
|
|> Task.async_stream(
|
||||||
|
fn orgfile ->
|
||||||
|
Logger.info(" exporting: #{orgfile}")
|
||||||
{orgfile, export_file(orgfile, notes_dir, output_dir)}
|
{orgfile, export_file(orgfile, notes_dir, output_dir)}
|
||||||
end)
|
end,
|
||||||
|
max_concurrency: max_concurrency,
|
||||||
|
timeout: :infinity,
|
||||||
|
ordered: false
|
||||||
|
)
|
||||||
|
|> Enum.map(fn {:ok, result} -> result end)
|
||||||
|
|
||||||
failures =
|
failures =
|
||||||
Enum.filter(results, fn
|
Enum.filter(results, fn
|
||||||
@@ -109,6 +123,10 @@ defmodule OrgGarden.Export do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp get_concurrency do
|
||||||
|
Application.get_env(:org_garden, :export_concurrency, @default_max_concurrency)
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Compute the expected `.md` path for a given `.org` file.
|
Compute the expected `.md` path for a given `.org` file.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user