|
|
|
@ -715,22 +715,14 @@ class CollectorApp: |
|
|
|
|
|
|
|
target = self._build_unique_backup_target(backup_dir, file_path) |
|
|
|
|
|
|
|
try: |
|
|
|
shutil.move(str(file_path), str(target)) |
|
|
|
if self._move_file_transactional(file_path, target, row_index): |
|
|
|
self.log("第%d行源文件已转移至备份: %s -> %s" % (row_index, file_path.name, target)) |
|
|
|
return True |
|
|
|
except FileNotFoundError: |
|
|
|
self.log("第%d行源文件在备份时已被处理,忽略重复备份: %s" % (row_index, file_path.name)) |
|
|
|
return True |
|
|
|
except Exception as e: |
|
|
|
self.log("第%d行源文件备份转移失败: %s, 原因: %s" % (row_index, file_path.name, e)) |
|
|
|
|
|
|
|
self.log("第%d行源文件备份转移失败: %s" % (row_index, file_path.name)) |
|
|
|
return False |
|
|
|
|
|
|
|
def _build_unique_backup_target(self, backup_dir, file_path): |
|
|
|
target = backup_dir / file_path.name |
|
|
|
if not target.exists(): |
|
|
|
return target |
|
|
|
|
|
|
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f") |
|
|
|
base_name = file_path.stem |
|
|
|
suffix = file_path.suffix |
|
|
|
@ -741,6 +733,56 @@ class CollectorApp: |
|
|
|
index += 1 |
|
|
|
return candidate |
|
|
|
|
|
|
|
def _move_file_transactional(self, source_file, target_file, row_index): |
|
|
|
try: |
|
|
|
source_file.rename(target_file) |
|
|
|
return True |
|
|
|
except FileNotFoundError: |
|
|
|
self.log("第%d行源文件在备份时已被处理,忽略重复备份: %s" % (row_index, source_file.name)) |
|
|
|
return True |
|
|
|
except Exception: |
|
|
|
pass |
|
|
|
|
|
|
|
temp_target = target_file.parent / ("%s.__tmp__.%d" % (target_file.name, int(time.time() * 1000))) |
|
|
|
try: |
|
|
|
shutil.copy2(str(source_file), str(temp_target)) |
|
|
|
if target_file.exists(): |
|
|
|
target_file = self._build_unique_backup_target(target_file.parent, source_file) |
|
|
|
temp_target.replace(target_file) |
|
|
|
except Exception as e: |
|
|
|
try: |
|
|
|
if temp_target.exists(): |
|
|
|
temp_target.unlink() |
|
|
|
except Exception: |
|
|
|
pass |
|
|
|
self.log("第%d行复制到备份目录失败: %s, 原因: %s" % (row_index, source_file.name, e)) |
|
|
|
return False |
|
|
|
|
|
|
|
if self._delete_source_with_retry(source_file): |
|
|
|
return True |
|
|
|
|
|
|
|
try: |
|
|
|
if target_file.exists(): |
|
|
|
target_file.unlink() |
|
|
|
except Exception as rollback_error: |
|
|
|
self.log("第%d行回滚备份文件失败: %s, 原因: %s" % (row_index, target_file, rollback_error)) |
|
|
|
return False |
|
|
|
|
|
|
|
def _delete_source_with_retry(self, file_path, retry_times=6, retry_interval=0.3): |
|
|
|
for idx in range(max(1, retry_times)): |
|
|
|
try: |
|
|
|
file_path.unlink() |
|
|
|
return True |
|
|
|
except FileNotFoundError: |
|
|
|
return True |
|
|
|
except Exception as e: |
|
|
|
if idx < retry_times - 1: |
|
|
|
time.sleep(retry_interval) |
|
|
|
continue |
|
|
|
self.log("删除源文件失败: %s, 原因: %s" % (file_path.name, e)) |
|
|
|
return False |
|
|
|
return False |
|
|
|
|
|
|
|
def _upload_file(self, row, file_path): |
|
|
|
url = self._base_url() + "/collector/client/upload" |
|
|
|
data = { |
|
|
|
|