require "gds_api/content_store"
require "active_support/core_ext/hash/keys"

# This lives here and not in the GDS API adapters
# because no other application should be writing
# to the content store.
class ContentStoreWriter < GdsApi::ContentStore
  def put_content_item(base_path:, content_item:)
    put_json(content_item_url(base_path), content_item)
  end

  def put_publish_intent(base_path:, publish_intent:)
    put_json(publish_intent_url(base_path), publish_intent)
  end

  def get_publish_intent(base_path)
    get_json(publish_intent_url(base_path))
  end

  def delete_publish_intent(base_path)
    delete_json(publish_intent_url(base_path))
  end

  def delete_content_item(base_path)
    delete_json(content_item_url(base_path))
  end

private

  def publish_intent_url(base_path)
    "#{endpoint}/publish-intent#{base_path}"
  end
end

require "gds_api/content_store"
require "active_support/core_ext/hash/keys"

# This lives here and not in the GDS API adapters
# because no other application should be writing
# to the content store.
class ContentStoreWriter < GdsApi::ContentStore
  def put_content_item(base_path:, content_item:)
    with_lock(base_path, :content_item) do
      put_json(content_item_url(base_path), content_item)
    end
  end

  def put_publish_intent(base_path:, publish_intent:)
    with_lock(base_path, :publish_intent) do
      put_json(publish_intent_url(base_path), publish_intent)
    end
  end

  def get_publish_intent(base_path)
    get_json(publish_intent_url(base_path))
  end

  def delete_publish_intent(base_path)
    with_lock(base_path, :publish_intent) do
      delete_json(publish_intent_url(base_path))
    end
  end

  def delete_content_item(base_path)
    with_lock(base_path, :content_item) do
      delete_json(content_item_url(base_path))
    end
  end

private

  def publish_intent_url(base_path)
    "#{endpoint}/publish-intent#{base_path}"
  end

  def with_lock(*args)
    # use endpoint to lock to a specific hostname
    lock_name = ([endpoint] + args).map(&:to_s).join("_")

    DistributedLock.lock(lock_name) { yield }
  end
end

Use DistributedLock when writing to content store
Use DistributedLock when writing to content store

This is to ensure that we don't make writes to the content store
concurrently. When this happens we can end up with the content store
being out of sync as it doesn't perform any locking.

You might wonder why this is being fixed here rather than in the Content
Store where it would probably make more sense. The reason that is done
here is to not contribute new complexity to the Content Store in line
with the goal that it can gradually become an S3 bucket of flat files.
So long as there is only one app writing to Content Store (this one)
it's fine to solve it here.
