From 1d4f20429e443fba47797198a8aafc812a0675d8 Mon Sep 17 00:00:00 2001 From: "shimoda.m@nds-tyo.co.jp" Date: Fri, 6 Jun 2025 16:30:31 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=BB=A2=E9=80=81=E5=89=8D=E3=81=AB?= =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=83=97=E3=83=AC=E3=83=95?= =?UTF-8?q?=E3=82=A3=E3=83=83=E3=82=AF=E3=82=B9=E3=81=AE=E9=87=8D=E8=A4=87?= =?UTF-8?q?=E3=82=92=E7=A2=BA=E8=AA=8D=E3=81=99=E3=82=8B=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AB=E4=BF=AE=E6=AD=A3=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-transfer-receive-file/src/main.py | 69 ++++++++++++++++++-- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/ecs/jskult-transfer-receive-file/src/main.py b/ecs/jskult-transfer-receive-file/src/main.py index 55a5f847..3348c5af 100644 --- a/ecs/jskult-transfer-receive-file/src/main.py +++ b/ecs/jskult-transfer-receive-file/src/main.py @@ -1,5 +1,9 @@ """実消化&アルトマーク データ転送処理""" +import itertools +import os +import re + from src.aws.s3 import (JskIOBucket, TransferResultOutputBucket, UltmarcBucket, UltmarcImportBucket) from src.error.exceptions import BatchOperationException @@ -32,12 +36,12 @@ def exec(): # 日次バッチ処理中の場合、後続の処理は行わない if batch_processing_flag == constants.BATCH_ACTF_BATCH_START: - logger.error('日次バッチ処理中のため、日次バッチ処理を終了します。') + logger.error('日次バッチ処理中のため、実消化&アルトマークデータ転送を終了します。') return constants.BATCH_EXIT_CODE_SUCCESS # dump取得が正常終了していない場合、後続の処理は行わない if dump_status_kbn != constants.DUMP_STATUS_KBN_COMPLETE: - logger.error('dump取得が正常終了していないため、日次バッチ処理を終了します。') + logger.error('dump取得が正常終了していないため、実消化&アルトマークデータ転送を終了します。') return constants.BATCH_EXIT_CODE_SUCCESS logger.info(f'処理日={syor_date}') @@ -54,10 +58,45 @@ def exec(): jsk_receive_file_list = None try: jsk_io_bucket = JskIOBucket() - jsk_receive_file_list: str = jsk_io_bucket.get_file_list() + jsk_receive_file_list: list[str] = jsk_io_bucket.get_file_list() except Exception as e: logger.exception(f'実消化データリスト取得に失敗しました。{e}') return constants.BATCH_EXIT_CODE_SUCCESS + + # 実消化データリストの中で、ファイル種類(ファイル名のプレフィックス)が重複するものがあるかどうかをチェックする。 + # 1) プレフィックスごとにマップを作り、該当するファイル名をリストで集める + # 以下のようなマップが作られる + # { + # "TRN_RESULT_DATA": ["TRN_RESULT_DATA_20250606102030.zip", + # "TRN_RESULT_DATA_20250606112030.zip"], + # "TRN_Recive_Inventry": ["TRN_Recive_Inventry_20250606102030.zip"], + # ... + # } + prefix_map: dict[str, list[str]] = {} + for filename in jsk_receive_file_list: + p = extract_prefix(filename) + prefix_map.setdefault(p, []).append(filename) + + # 2) 重複しているプレフィックスを探す + duplicates = {prefix: file_list for prefix, + file_list in prefix_map.items() if len(file_list) > 1} + + # 3) 重複があれば転送一覧から除外する + if duplicates: + # マップをフラットなリストに変換する + duplicate_files = list( + itertools.chain.from_iterable(duplicates.values())) + logger.warning( + f'実消化データの中で一部重複データがあります。重複データは転送から除外します。重複データ一覧: {duplicate_files}') + # 転送しなかったファイルもバックアップに移動させる + for filename in duplicate_files: + jsk_io_bucket.backup_file(filename, syor_date) + jsk_io_bucket.delete_file(filename) + + # S3内のファイル数と重複ファイルの差集合を取ることで、要素を削除 + jsk_receive_file_list = list( + set(jsk_receive_file_list) - set(duplicate_files)) + logger.info(f'I-4 実消化データリスト取得終了。取得データ一覧:{jsk_receive_file_list}') # ④ 取得した実消化データのリストでループ開始 @@ -72,7 +111,7 @@ def exec(): # ⑧ 転送が完了したファイル名を転送データリストに追加する # ファイル名のみ切り出して追加 transfer_file_lists['jsk_transfer_list'].append( - receive_file['filename'].split('/')[1]) + receive_file.split('/')[1]) # ⑨ ループ終了後、実消化データ転送終了ログ(I-6)を出力する logger.info(f'I-6 実消化データ転送処理終了') @@ -102,12 +141,13 @@ def exec(): # ⑮ 転送が完了したファイル名を転送データリストに追加する # ファイル名のみ切り出して追加 transfer_file_lists['ult_transfer_list'].append( - receive_file['filename'].split('/')[1]) + receive_file.split('/')[1]) # ⑯ ループ終了後、アルトマークデータ転送終了ログ(I-10)を出力する - logger.info(f'I-6 実消化データ転送処理終了') + logger.info(f'I-10 アルトマークデータ転送処理終了') # ⑰ 転送データリストをJSONファイル化し、S3バケットにアップロードする + logger.info(f'I-11 データ転送結果アップロード') TransferResultOutputBucket().put_transfer_result(transfer_file_lists, syor_date) # ⑱ 処理終了ログ(I-12)を出力する @@ -118,3 +158,20 @@ def exec(): except Exception as e: logger.exception(f'実消化&アルトマーク データ転送処理中に想定外のエラーが発生しました {e}') raise e + + +def extract_prefix(filename: str) -> str: + """ + ファイル名から『タイムスタンプ部分 + 拡張子』を除いたプレフィックスを返す。 + 例: "TRN_RESULT_DATA_20250606102030.zip" -> "TRN_RESULT_DATA" + """ + # 拡張子を取り除く + file, ext = os.path.splitext(os.path.basename(filename)) + # ファイル名の末尾がタイムスタンプ(数字14桁)である想定なので、最後の '_' 以降を削除 + # TRN_RESULT_DATA_20250606102030 -> ["TRN_RESULT_DATA", "20250606102030"] + parts = file.rsplit('_', 1) + if len(parts) == 2 and re.fullmatch(r"\d{14}", parts[1]): + return parts[0] + else: + # 「最後がタイムスタンプじゃない」場合、そのままのファイル名全体を返す + return filename