こんにちわ。プロフェッショナルサービス事業部の小松です。
少し前になりますが、S3が条件付き書き込み(conditional writes)に対応したと発表がありました!
https://aws.amazon.com/jp/about-aws/whats-new/2024/08/amazon-s3-conditional-writes/

条件付き書き込みとは

条件付き書き込みとは、オブジェクトを書き込む際に、オブジェクトの存在確認を事前に行い、既にオブジェクトが存在した場合は上書きを回避することができる機能になります。

この機能が実装されたことにより、事前のオブジェクトの存在チェックを行ったり、並列で実行されるジョブが誤って同一のオブジェクトを上書きしてしまうような事故の回避を、プログラムの実装無しで行うことができるようになります。

やってみよう

事前に用意したS3にサンプルのテキストをアップロードしておきます。

[cloudshell-user@ip-10-132-79-62 sample]$ cat sample.txt 
write test1
[cloudshell-user@ip-10-132-79-62 sample]$ aws s3 cp sample.txt s3://komatsu-conditional-writes-test/sample.txt
upload: ./sample.txt to s3://komatsu-conditional-writes-test/sample.txt
[cloudshell-user@ip-10-132-79-62 sample]$ aws s3 ls s3://komatsu-conditional-writes-test
2024-09-18 04:05:50         12 sample.txt

次に、オプション無しで同じ名前でファイルをアップロードしてみます。

[cloudshell-user@ip-10-132-79-62 sample]$ cat sample_new.txt 
write test2
[cloudshell-user@ip-10-132-79-62 sample]$ aws s3 cp sample_new.txt s3://komatsu-conditional-writes-test/sample.txt
upload: ./sample_new.txt to s3://komatsu-conditional-writes-test/sample.txt
[cloudshell-user@ip-10-132-79-62 sample]$ aws s3 ls s3://komatsu-conditional-writes-test
2024-09-18 04:10:37         12 sample.txt

タイムスタンプが更新されているので、オブジェクトは置き換わっているように見えます。

念のため、中身を確認してみたところ置き換わっていることが確認できました。

次に、今回実装されたオプションを付けて上書きを試みてみます。

[cloudshell-user@ip-10-132-79-62 sample]$ aws s3 cp --if-none-match sample.txt s3://komatsu-conditional-writes-test/sample.txt

Unknown options: --if-none-match

(#°Д°) うぉぉぉぃ
AWS CLIで対応してないんかい!と思ったのですが、よく見てみると
「PutObject または CompleteMultipartUpload API リクエストを使用して条件付き書き込みを実行できます。」
ってちゃんと書いてありました。失礼しました。。。

[cloudshell-user@ip-10-132-79-62 sample]$ aws s3api put-object help
___snip___
       --if-none-match (string)
          Uploads  the object only if the object key name does not already ex-
          ist in the bucket specified. Otherwise, Amazon S3 returns a 412 Pre-
          condition Failed error.

          If a conflicting operation occurs during the upload S3 returns a 409
          ConditionalRequestConflict response. On a  409  failure  you  should
          retry the upload.

          Expects the '*' (asterisk) character.

          For  more  information about conditional requests, see RFC 7232 , or
          Conditional requests in the Amazon S3 User Guide .

あらためてこのオプションで確認してみましょう。
–if-none-match “*”を付けてput-objectを実行してみます。

[cloudshell-user@ip-10-132-79-62 sample]$ aws s3 ls s3://komatsu-conditional-writes-test
2024-09-18 04:10:37         12 sample.txt
[cloudshell-user@ip-10-132-79-62 sample]$ aws s3api put-object --bucket komatsu-conditional-writes-test --key "sample.txt" --body ./sample.txt --if-none-match "*"

An error occurred (PreconditionFailed) when calling the PutObject operation: At least one of the pre-conditions you specified did not hold
[cloudshell-user@ip-10-132-79-62 sample]$ aws s3 ls s3://komatsu-conditional-writes-test
2024-09-18 04:10:37         12 sample.txt

エラーになってタイムスタンプも更新されていないですね。
エラーの内容としてはPreconditionFailedとなっていました。ちゃんとオブジェクトが存在しているとエラーを返してくれるようですね。

まとめ

冒頭でも書きましたが、オブジェクトの存在チェックを自前で実装する必要がなくなるのが大きなメリットになるかと思います。
今後は積極的に使っていくのは大前提ですが、このようなネイティブな機能追加はとても助かる一方、今までに作ったものをわざわざ置き換えるかどうかを個人的には毎回悩みます。
みなさんも、コードの書き方や呼び出し回数などにより、改修にかかる工数やAPIコールの回数による料金など、色々な観点で比較検討してみてはいかがでしょうか。