chore: more transactions with filesystem actions cleanup
This commit is contained in:
@@ -88,10 +88,10 @@ defmodule BDS.Metadata do
|
||||
|> Repo.update!()
|
||||
|
||||
persist_setting(project_id, "project", stringify_project_metadata(project_metadata), now)
|
||||
write_project_metadata_files(updated_project, state, project_metadata)
|
||||
load_state(updated_project)
|
||||
{updated_project, project_metadata}
|
||||
end)
|
||||
|> unwrap_transaction()
|
||||
|> flush_project_metadata_update(state)
|
||||
|> maybe_backfill_embeddings(project_id, state, project_metadata)
|
||||
end
|
||||
|
||||
@@ -106,8 +106,7 @@ defmodule BDS.Metadata do
|
||||
|> Enum.sort()
|
||||
|
||||
persist_setting(project.id, "categories", %{"categories" => categories}, now)
|
||||
write_categories_json(project, categories)
|
||||
%{state | categories: categories}
|
||||
{%{state | categories: categories}, fn -> write_categories_json(project, categories) end}
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -119,9 +118,14 @@ defmodule BDS.Metadata do
|
||||
|
||||
persist_setting(project.id, "categories", %{"categories" => categories}, now)
|
||||
persist_setting(project.id, "category_meta", %{"categories" => category_settings}, now)
|
||||
write_categories_json(project, categories)
|
||||
write_category_meta_json(project, category_settings)
|
||||
%{state | categories: categories, category_settings: category_settings}
|
||||
|
||||
{%{state | categories: categories, category_settings: category_settings},
|
||||
fn ->
|
||||
with :ok <- write_categories_json(project, categories),
|
||||
:ok <- write_category_meta_json(project, category_settings) do
|
||||
:ok
|
||||
end
|
||||
end}
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -133,8 +137,9 @@ defmodule BDS.Metadata do
|
||||
category_settings = Map.put(state.category_settings, category, normalized)
|
||||
|
||||
persist_setting(project.id, "category_meta", %{"categories" => category_settings}, now)
|
||||
write_category_meta_json(project, category_settings)
|
||||
%{state | category_settings: category_settings}
|
||||
|
||||
{%{state | category_settings: category_settings},
|
||||
fn -> write_category_meta_json(project, category_settings) end}
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -144,8 +149,9 @@ defmodule BDS.Metadata do
|
||||
update_state(project_id, fn project, state, now ->
|
||||
publishing_preferences = normalize_publishing_preferences(prefs)
|
||||
persist_setting(project.id, "publishing", publishing_preferences, now)
|
||||
write_publishing_json(project, publishing_preferences)
|
||||
%{state | publishing_preferences: publishing_preferences}
|
||||
|
||||
{%{state | publishing_preferences: publishing_preferences},
|
||||
fn -> write_publishing_json(project, publishing_preferences) end}
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -176,13 +182,10 @@ defmodule BDS.Metadata do
|
||||
)
|
||||
|
||||
persist_setting(project_id, "publishing", filesystem_state.publishing_preferences, now)
|
||||
write_project_json(updated_project, stringify_project_metadata(filesystem_state))
|
||||
write_categories_json(updated_project, filesystem_state.categories)
|
||||
write_category_meta_json(updated_project, filesystem_state.category_settings)
|
||||
write_publishing_json(updated_project, filesystem_state.publishing_preferences)
|
||||
load_state(updated_project)
|
||||
updated_project
|
||||
end)
|
||||
|> unwrap_transaction()
|
||||
|> flush_synced_project_metadata(filesystem_state)
|
||||
end
|
||||
|
||||
@spec flush_project_metadata_to_filesystem(String.t()) :: {:ok, metadata_state()}
|
||||
@@ -200,10 +203,9 @@ defmodule BDS.Metadata do
|
||||
state = load_state(project)
|
||||
now = Persistence.now_ms()
|
||||
|
||||
Repo.transaction(fn ->
|
||||
updater.(project, state, now)
|
||||
end)
|
||||
Repo.transaction(fn -> updater.(project, state, now) end)
|
||||
|> unwrap_transaction()
|
||||
|> flush_state_update()
|
||||
end
|
||||
|
||||
defp load_state(project) do
|
||||
@@ -338,11 +340,40 @@ defmodule BDS.Metadata do
|
||||
}
|
||||
end
|
||||
|
||||
defp flush_project_metadata_update({:ok, {updated_project, project_metadata}}, state) do
|
||||
with :ok <- write_project_metadata_files(updated_project, state, project_metadata) do
|
||||
{:ok, load_state(updated_project)}
|
||||
end
|
||||
end
|
||||
|
||||
defp flush_project_metadata_update(error, _state), do: error
|
||||
|
||||
defp flush_synced_project_metadata({:ok, updated_project}, filesystem_state) do
|
||||
with :ok <- write_project_json(updated_project, stringify_project_metadata(filesystem_state)),
|
||||
:ok <- write_categories_json(updated_project, filesystem_state.categories),
|
||||
:ok <- write_category_meta_json(updated_project, filesystem_state.category_settings),
|
||||
:ok <- write_publishing_json(updated_project, filesystem_state.publishing_preferences) do
|
||||
{:ok, load_state(updated_project)}
|
||||
end
|
||||
end
|
||||
|
||||
defp flush_synced_project_metadata(error, _filesystem_state), do: error
|
||||
|
||||
defp flush_state_update({:ok, {state, write_files}}) when is_function(write_files, 0) do
|
||||
with :ok <- write_files.() do
|
||||
{:ok, state}
|
||||
end
|
||||
end
|
||||
|
||||
defp flush_state_update(error), do: error
|
||||
|
||||
defp write_project_metadata_files(project, state, project_metadata) do
|
||||
write_project_json(project, stringify_project_metadata(project_metadata))
|
||||
write_categories_json(project, state.categories)
|
||||
write_category_meta_json(project, state.category_settings)
|
||||
write_publishing_json(project, state.publishing_preferences)
|
||||
with :ok <- write_project_json(project, stringify_project_metadata(project_metadata)),
|
||||
:ok <- write_categories_json(project, state.categories),
|
||||
:ok <- write_category_meta_json(project, state.category_settings),
|
||||
:ok <- write_publishing_json(project, state.publishing_preferences) do
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
defp write_project_json(project, project_json),
|
||||
@@ -363,7 +394,7 @@ defmodule BDS.Metadata do
|
||||
defp write_json(project, file_name, payload) do
|
||||
meta_dir = Path.join(Projects.project_data_dir(project), "meta")
|
||||
path = Path.join(meta_dir, file_name)
|
||||
:ok = Persistence.atomic_write(path, Jason.encode!(payload))
|
||||
Persistence.atomic_write(path, Jason.encode!(payload))
|
||||
end
|
||||
|
||||
defp read_json(project, file_name) do
|
||||
|
||||
@@ -66,10 +66,10 @@ defmodule BDS.Persistence do
|
||||
def parse_timestamp(_value), do: nil
|
||||
|
||||
def atomic_write(path, contents) when is_binary(path) and is_binary(contents) do
|
||||
:ok = File.mkdir_p(Path.dirname(path))
|
||||
temp_path = path <> ".tmp"
|
||||
|
||||
with :ok <- File.write(temp_path, contents),
|
||||
with :ok <- File.mkdir_p(Path.dirname(path)),
|
||||
:ok <- File.write(temp_path, contents),
|
||||
:ok <- File.rename(temp_path, path) do
|
||||
:ok
|
||||
else
|
||||
|
||||
@@ -84,11 +84,10 @@ defmodule BDS.Projects do
|
||||
})
|
||||
|> Repo.insert!()
|
||||
|
||||
{:ok, _templates} = Templates.rebuild_templates_from_files(project.id)
|
||||
project
|
||||
end)
|
||||
|> case do
|
||||
{:ok, project} -> {:ok, project}
|
||||
{:ok, project} -> rebuild_project_templates(project)
|
||||
{:error, reason} -> {:error, reason}
|
||||
end
|
||||
end
|
||||
@@ -127,11 +126,14 @@ defmodule BDS.Projects do
|
||||
})
|
||||
|> Repo.insert!()
|
||||
|
||||
{:ok, _templates} = Templates.rebuild_templates_from_files(project.id)
|
||||
project
|
||||
end)
|
||||
|> case do
|
||||
{:ok, project} -> sync_filesystem_metadata(project)
|
||||
{:ok, project} ->
|
||||
with {:ok, project} <- rebuild_project_templates(project) do
|
||||
sync_filesystem_metadata(project)
|
||||
end
|
||||
|
||||
{:error, reason} -> {:error, reason}
|
||||
end
|
||||
end
|
||||
@@ -217,6 +219,12 @@ defmodule BDS.Projects do
|
||||
end
|
||||
end
|
||||
|
||||
defp rebuild_project_templates(%Project{} = project) do
|
||||
with {:ok, _templates} <- Templates.rebuild_templates_from_files(project.id) do
|
||||
{:ok, project}
|
||||
end
|
||||
end
|
||||
|
||||
defp unique_slug(base_slug) do
|
||||
normalized = if base_slug in [nil, ""], do: "project", else: base_slug
|
||||
|
||||
|
||||
@@ -30,8 +30,9 @@ defmodule BDS.Tags do
|
||||
|> Repo.insert()
|
||||
|> case do
|
||||
{:ok, tag} ->
|
||||
write_tags_json(project_id)
|
||||
{:ok, tag}
|
||||
with :ok <- write_tags_json(project_id) do
|
||||
{:ok, tag}
|
||||
end
|
||||
|
||||
error ->
|
||||
error
|
||||
@@ -85,11 +86,14 @@ defmodule BDS.Tags do
|
||||
|> Repo.insert!()
|
||||
end)
|
||||
|
||||
write_tags_json(project_id)
|
||||
list_tags(project_id)
|
||||
end)
|
||||
|> case do
|
||||
{:ok, tags} -> {:ok, tags}
|
||||
{:ok, tags} ->
|
||||
with :ok <- write_tags_json(project_id) do
|
||||
{:ok, tags}
|
||||
end
|
||||
|
||||
{:error, reason} -> {:error, reason}
|
||||
end
|
||||
end
|
||||
@@ -111,8 +115,9 @@ defmodule BDS.Tags do
|
||||
|> Repo.update()
|
||||
|> case do
|
||||
{:ok, updated_tag} ->
|
||||
write_tags_json(updated_tag.project_id)
|
||||
{:ok, updated_tag}
|
||||
with :ok <- write_tags_json(updated_tag.project_id) do
|
||||
{:ok, updated_tag}
|
||||
end
|
||||
|
||||
error ->
|
||||
error
|
||||
@@ -135,10 +140,15 @@ defmodule BDS.Tags do
|
||||
end)
|
||||
|
||||
Repo.delete!(tag)
|
||||
write_tags_json(tag.project_id)
|
||||
Enum.map(affected_posts, & &1.id)
|
||||
end)
|
||||
|> case do
|
||||
{:ok, _} -> {:ok, :deleted}
|
||||
{:ok, post_ids} ->
|
||||
with :ok <- rewrite_published_posts(post_ids),
|
||||
:ok <- write_tags_json(tag.project_id) do
|
||||
{:ok, :deleted}
|
||||
end
|
||||
|
||||
{:error, reason} -> {:error, reason}
|
||||
end
|
||||
end
|
||||
@@ -168,11 +178,15 @@ defmodule BDS.Tags do
|
||||
|> Tag.changeset(%{name: normalized_name, updated_at: Persistence.now_ms()})
|
||||
|> Repo.update!()
|
||||
|
||||
write_tags_json(tag.project_id)
|
||||
updated_tag
|
||||
{updated_tag, Enum.map(affected_posts, & &1.id)}
|
||||
end)
|
||||
|> case do
|
||||
{:ok, updated_tag} -> {:ok, updated_tag}
|
||||
{:ok, {updated_tag, post_ids}} ->
|
||||
with :ok <- rewrite_published_posts(post_ids),
|
||||
:ok <- write_tags_json(tag.project_id) do
|
||||
{:ok, updated_tag}
|
||||
end
|
||||
|
||||
{:error, reason} -> {:error, reason}
|
||||
end
|
||||
end
|
||||
@@ -193,18 +207,23 @@ defmodule BDS.Tags do
|
||||
|
||||
Repo.transaction(fn ->
|
||||
source_names = Enum.map(source_tags, & &1.name)
|
||||
affected_posts = posts_with_any_tag(target_tag.project_id, source_names)
|
||||
|
||||
posts_with_any_tag(target_tag.project_id, source_names)
|
||||
|> Enum.each(fn post ->
|
||||
Enum.each(affected_posts, fn post ->
|
||||
updated_tags = merge_post_tags(post.tags || [], source_names, target_tag.name)
|
||||
update_post_tags(post, updated_tags)
|
||||
end)
|
||||
|
||||
Enum.each(source_tags, &Repo.delete!/1)
|
||||
write_tags_json(target_tag.project_id)
|
||||
Enum.map(affected_posts, & &1.id)
|
||||
end)
|
||||
|> case do
|
||||
{:ok, _} -> {:ok, :merged}
|
||||
{:ok, post_ids} ->
|
||||
with :ok <- rewrite_published_posts(post_ids),
|
||||
:ok <- write_tags_json(target_tag.project_id) do
|
||||
{:ok, :merged}
|
||||
end
|
||||
|
||||
{:error, reason} -> {:error, reason}
|
||||
end
|
||||
end
|
||||
@@ -213,7 +232,6 @@ defmodule BDS.Tags do
|
||||
defp write_tags_json(project_id) do
|
||||
project = Projects.get_project!(project_id)
|
||||
path = Path.join([Projects.project_data_dir(project), "meta", "tags.json"])
|
||||
:ok = File.mkdir_p(Path.dirname(path))
|
||||
|
||||
payload =
|
||||
project_id
|
||||
@@ -225,7 +243,7 @@ defmodule BDS.Tags do
|
||||
|> maybe_put("postTemplateSlug", tag.post_template_slug)
|
||||
end)
|
||||
|
||||
:ok = Persistence.atomic_write(path, Jason.encode!(payload))
|
||||
Persistence.atomic_write(path, Jason.encode!(payload))
|
||||
end
|
||||
|
||||
defp validate_unique_name(project_id, name) do
|
||||
@@ -312,8 +330,11 @@ defmodule BDS.Tags do
|
||||
post
|
||||
|> Post.changeset(%{tags: updated_tags, updated_at: Persistence.now_ms()})
|
||||
|> Repo.update!()
|
||||
end
|
||||
|
||||
Posts.rewrite_published_post(post.id)
|
||||
defp rewrite_published_posts(post_ids) do
|
||||
Enum.each(post_ids, &Posts.rewrite_published_post/1)
|
||||
:ok
|
||||
end
|
||||
|
||||
defp maybe_put(map, _key, nil), do: map
|
||||
|
||||
Reference in New Issue
Block a user