|
| 1 | +""" |
| 2 | +ファイルロックユーティリティ. |
| 3 | +
|
| 4 | +このモジュールは、複数プロセス間での排他制御を実現するための |
| 5 | +ファイルロック機能を提供します。同一ファイルに対する同時アクセスを |
| 6 | +防止するために使用されます。 |
| 7 | +""" |
| 8 | + |
1 | 9 | import os |
2 | 10 | import sys |
| 11 | +from typing import Any, Optional, TextIO |
3 | 12 |
|
4 | 13 | import portalocker |
5 | 14 |
|
6 | 15 |
|
7 | 16 | class FileLock: |
8 | | - def __init__(self, lockfile): |
| 17 | + """ |
| 18 | + ファイルベースの排他制御ロック. |
| 19 | + |
| 20 | + ファイルシステムを使用してプロセス間の排他制御を実現します。 |
| 21 | + コンテキストマネージャーとして使用することで、自動的にロックの |
| 22 | + 取得と解放を行います。 |
| 23 | + """ |
| 24 | + |
| 25 | + def __init__(self, lockfile: str) -> None: |
| 26 | + """ |
| 27 | + ファイルロックを初期化する. |
| 28 | + |
| 29 | + Args: |
| 30 | + lockfile: ロックファイルのパス |
| 31 | + """ |
9 | 32 | self.lockfile = lockfile |
10 | | - self.fp = None |
| 33 | + self.fp: Optional[TextIO] = None |
11 | 34 |
|
12 | | - def acquire(self): |
| 35 | + def acquire(self) -> None: |
| 36 | + """ |
| 37 | + ロックを取得する. |
| 38 | + |
| 39 | + 指定されたロックファイルに対して排他ロックを取得します。 |
| 40 | + 既に他のプロセスがロックを保持している場合は、プログラムを終了します。 |
| 41 | + |
| 42 | + Raises: |
| 43 | + SystemExit: 他のプロセスがロックを保持している場合 |
| 44 | + """ |
| 45 | + # ロックファイルを書き込みモードで開く |
13 | 46 | self.fp = open(self.lockfile, "w") |
| 47 | + |
14 | 48 | try: |
| 49 | + # 排他ロック + ノンブロッキングでロックを取得 |
15 | 50 | portalocker.lock(self.fp, portalocker.LOCK_EX | portalocker.LOCK_NB) |
16 | 51 | except portalocker.LockException: |
| 52 | + # ロックの取得に失敗した場合(他のプロセスが保持中) |
17 | 53 | print(f"他のプロセスがロック中です: {self.lockfile}") |
18 | 54 | sys.exit(1) |
19 | 55 |
|
20 | | - def release(self): |
| 56 | + def release(self) -> None: |
| 57 | + """ |
| 58 | + ロックを解放する. |
| 59 | + |
| 60 | + 取得したロックを解放し、ファイルハンドルを閉じます。 |
| 61 | + エラーが発生してもプログラムの実行は継続されます。 |
| 62 | + """ |
21 | 63 | if self.fp: |
22 | 64 | try: |
| 65 | + # ロックを解放 |
23 | 66 | portalocker.unlock(self.fp) |
24 | 67 | except Exception: |
| 68 | + # エラーが発生してもプログラムを継続 |
| 69 | + # (プロセス終了時に自動的にロックは解放される) |
25 | 70 | pass |
| 71 | + |
| 72 | + # ファイルハンドルを閉じる |
26 | 73 | self.fp.close() |
27 | 74 | self.fp = None |
28 | 75 |
|
29 | | - def __enter__(self): |
| 76 | + def __enter__(self) -> "FileLock": |
| 77 | + """ |
| 78 | + コンテキストマネージャーの開始処理. |
| 79 | + |
| 80 | + with文で使用した際にロックを自動的に取得します。 |
| 81 | + |
| 82 | + Returns: |
| 83 | + 自分自身のインスタンス |
| 84 | + """ |
30 | 85 | self.acquire() |
31 | 86 | return self |
32 | 87 |
|
33 | | - def __exit__(self, exc_type, exc_val, exc_tb): |
| 88 | + def __exit__( |
| 89 | + self, |
| 90 | + exc_type: Optional[type], |
| 91 | + exc_val: Optional[Exception], |
| 92 | + exc_tb: Optional[Any], |
| 93 | + ) -> None: |
| 94 | + """ |
| 95 | + コンテキストマネージャーの終了処理. |
| 96 | + |
| 97 | + with文のブロックを抜ける際にロックを自動的に解放します。 |
| 98 | + |
| 99 | + Args: |
| 100 | + exc_type: 例外の型 |
| 101 | + exc_val: 例外の値 |
| 102 | + exc_tb: トレースバック情報 |
| 103 | + """ |
34 | 104 | self.release() |
0 commit comments