【実務・中級編】【上級者向け】Project Server/Online環境におけるチェックアウト・チェックインのAPI制御 – Project VBA解析バイブル

スポンサーリンク

Project Server/Onlineの闇を制す:チェックアウト・チェックインのAPI制御を極める

諸君、Project ServerやProject Online(PWA)の環境で自動化ツールを組む際、多くのエンジニアが「読み取り専用で開いてしまう」「誰かが開いていて更新できない」という壁に突き当たる。

大半のチュートリアルは、表面的なメソッドをなぞるだけで終わる。だが、現場で求められるのは「排他制御の競合をいかにエレガントに、かつ堅牢に処理するか」という一点に尽きる。今回は、PWA環境におけるProjectのライフサイクル制御、すなわち「チェックアウトとチェックインの真髄」を叩き込む。

1. なぜ「単純なOpen」では失敗するのか

Project Server環境では、ファイルは単なるバイナリではなく、SQL Server上のデータセットとして管理されている。`Project.Open` を叩く際、バックグラウンドでは以下の処理が走っている。

1. チェックアウト要求: サーバーに対し、自分のUIDで対象プロジェクトをロックする。
2. データストリーミング: サーバーからローカルキャッシュへプロジェクトデータを展開。
3. セッション維持: 編集権限を持つクライアントとしてサーバーと通信。

ここで問題になるのが、「前のセッションの残骸(ゾンビ・セッション)」だ。異常終了したVBAがチェックアウト状態を放置すると、サーバーは「他の誰かが編集中」と判断し、後続のプロセスを拒絶する。これを力技で突破するには、サーバーサイドのAPIを利用した「強制チェックイン」の設計が必須となる。

2. 堅牢な設計指針:3つの掟

1. Read/Writeの明示的指定: `Open`メソッドの第2引数(`ReadOnly`)を盲信しないこと。サーバー側の状態を先にAPIで確認し、必要なら強制チェックインを試行するロジックを挟む。
2. イベントハンドラの活用: `ProjectBeforeClose`や`ProjectBeforeSave`をフックし、いかなる終了コードであっても確実に`CheckIn`を呼び出す「終了保証」を組み込む。
3. エラーハンドリングの多重層: 通信エラーと排他エラーを明確に切り分けること。

3. 実践コード:強制チェックイン機能を備えたプロジェクト制御

以下は、Project Online環境でプロジェクトを安全に開き、必要に応じて強制的にチェックインを行うための汎用的なVBAプロシージャだ。

‘ プロジェクトを開く際の堅牢なラッパー
Public Sub SafeOpenProject(ByVal projectPath As String)
Dim proj As Project

On Error GoTo ErrorHandler

‘ 1. プロジェクトをReadOnlyで試行してチェックアウト状態を確認
‘ または、事前にProject Server API(PSI/REST)で状態を確認するのがベスト

Set proj = Application.Projects.Open(projectPath, ReadOnly:=False)

‘ 成功した場合は処理を実行
Debug.Print “プロジェクトの制御権を取得しました: ” & proj.Name

Exit Sub

ErrorHandler:
‘ 2. 排他エラー(エラー番号 1101 等)を検知した場合のリカバリ
If Err.Number = 1101 Then
Debug.Print “プロジェクトが編集中です。強制チェックインを試行します。”
Call ForceCheckIn(projectPath)
Resume ‘ リトライ
Else
MsgBox “予期せぬエラー: ” & Err.Description
End If
End Sub

‘ 強制チェックイン処理(Project Server/Online環境用)
Public Sub ForceCheckIn(ByVal projectPath As String)
‘ 実際にはPSI (Project Server Interface) や REST API を使用して
‘ チェックアウト状態を強制解除する処理を呼び出す
‘ VBAから直接行う場合は、Project オブジェクトの CheckIn メソッドを使用

Dim proj As Project
Set proj = Application.ActiveProject

If Not proj Is Nothing Then
‘ Save: True とすることで変更をサーバーにコミットしてからチェックイン
proj.CheckIn Save:=True, Comment:=”Auto-recovery check-in by Chief Architect Tool”
Debug.Print “強制チェックインが完了しました。”
End If
End Sub

4. アーキテクトからの助言:運用を安定させるために

コードを見て「なぜ `CheckIn` を強制するのか」と疑問に思うかもしれない。答えはシンプルだ。「人間が手動でチェックインを忘れることを前提にシステムを組むから」だ。

  • データベース連携の注意点:

プロジェクトのベースライン設定やカスタムフィールド更新を行う際、チェックインを行うとサーバー側で「再計算」が走る。大量のプロジェクトを一括処理する場合、1プロジェクトごとにチェックインを繰り返すとAPIリクエスト制限(Throttling)に抵触する可能性がある。バッチ処理時は「一括チェックアウト → 連続編集 → 最後に一括チェックイン」というトランザクション設計を意識すること。

  • 保守性の極意:

APIの呼び出し部分は、メインのビジネスロジックから完全に分離せよ。`ProjectController` クラスといったクラスモジュールを作成し、`OpenProject` と `CloseProject` のメソッドにチェックイン/チェックアウトのライフサイクルをカプセル化する。これにより、将来的にREST APIへ移行する際も、メインロジックを変更することなく対応可能になる。

結びに代えて

自動化とは、単に手作業を置き換えることではない。「システムが陥りやすいエラー状態を先回りして排除し、常にクリーンな状態を維持する仕組みを作ること」である。

このアーキテクチャを採用すれば、君の作成するツールは「たまに止まる不安定なマクロ」から、「サーバーの整合性を守る頼れる自動化エージェント」へと進化するはずだ。次のステップとして、Project OnlineのREST APIを直接叩くラッパーの実装を検討してみてほしい。君ならできるはずだ。

タイトルとURLをコピーしました