【極限の設計】ネットワーク切断を「想定内」に変える:AutoCAD VBAにおけるShadow-Save(一時退避)同期システムの実装
業務自動化の世界において、最も恐ろしいのは「コードが動かないこと」ではない。「コードが動いている最中に、データが死ぬこと」だ。
特に、大規模な設計プロジェクトにおいて、DWGファイルがネットワーク上のファイルサーバー(UNCパス)に置かれているケースは多い。ここで、開発者が最も陥りやすい罠がある。それは、`ThisDrawing.Save` や `SaveAs` を単に呼び出すだけの、あまりに無防備な実装だ。
ネットワークの一時的な瞬断、あるいはセッションのタイムアウトが発生した瞬間、書き込み中のDWGファイルは破損(Corrupt)し、設計者の数時間を、あるいは数日間の努力をゴミに変える。
今日は、そんな「運任せの保存」を卒業し、プロフェッショナルとして実装すべき「トランザクション型・ローカル退避&復旧同期システム」の設計思想とその実装を伝授する。
1. なぜ、標準のAutoSaveでは不十分なのか
AutoCADには標準の自動保存機能がある。しかし、エンジニアが構築する「業務効率化ツール」の文脈では、以下の3点が致命的な欠落となる。
1. コンテキストの欠如: 標準のAutoSaveは「図面データ」は守るが、VBA側で保持している「処理中の変数状態」や「外部DBとの連携ログ」までは同期できない。
2. 書き込み失敗への無策: ネットワーク切断時に `Save` コマンドが走ると、OSレベルでの書き込みエラーが発生し、最悪の場合、ファイルポインタが壊れた状態でファイルがロックされる。
3. 復旧プロセスの自動化不足: 復旧は常に「手動」であり、どのファイルが、どのタイミングで、どの程度最新だったのかを判別するロジックが欠落している。
我々が構築すべきは、「ネットワークへの書き込みを『不確実な試行』と定義し、失敗した瞬間に『確実なローカル保存』へフォールバックする」、極めて堅牢な設計である。
2. アーキテクチャ設計:Shadow-Saveパターン
設計の核となるのは、以下の3つのフェーズからなるサイクルだ。
A. Pre-flight Check(事前検証)
保存を実行する前に、ターゲットとなるネットワークパスへの書き込み権限と接続性を検証する。
B. Shadow-Write(二段構えの保存)
1. Primary Attempt: ネットワークパスへの `SaveAs` を試行。
2. Fallback (The Shadow): ネットワークエラー(Error 70: Permission Denied, Error 76: Path not found等)をキャッチした瞬間、即座にローカルの隠しディレクトリへ、タイムスタンプとシリアル番号を付与した名称で退避させる。
C. Synchronization Logic(復旧同期)
次回起動時、ローカルの退避フォルダをスキャンし、サーバー上のファイルよりも新しい(あるいはサーバー上に存在しない)「孤立したシャドウファイル」を発見した場合、ユーザーに同期(Overwrite or Keep both)を促す。
3. プロダクション・コード例
以下に、実務に耐えうる堅牢な実装例を示す。ここでは、ファイル操作の信頼性を高めるために `FileSystemObject` (FSO) を活用する。
※このコードを使用するには、VBAエディタの [ツール] -> [参照設定] から “Microsoft Scripting Runtime” にチェックを入れておくこと。
Option Explicit
' ==============================================================================
' Module: ShadowSaveManager
' Description: ネットワーク切断を想定した堅牢な保存・復旧システム
' Author: Chief Architect
' ==============================================================================
Private Const LOCAL_CACHE_DIR As String = "C:\ProgramData\YourCompany\AutoCAD_ShadowCache\"
''' <summary>
''' 高度な保存プロセスを実行する。
''' ネットワークへの保存に失敗した場合、ローカルへ緊急退避を行う。
''' </summary>
Public Sub ExecuteSafeSave()
Dim targetPath As String
Dim localPath As String
Dim fileName As String
Dim fso As New FileSystemObject
Dim serialNo As String
On Error GoTo ErrorHandler
' 1. 現在の図面情報を取得
targetPath = ThisDrawing.FullName
fileName = ThisDrawing.Name
serialNo = Format(Now, "yyyymmdd_hhmmss")
' 2. ローカルキャッシュディレクトリの存在確認と作成
If Not fso.FolderExists(LOCAL_CACHE_DIR) Then
' 権限エラーを避けるため、適切なディレクトリを作成(実際には管理者権限に注意)
fso.CreateFolder LOCAL_CACHE_DIR
End If
' 3. ネットワークへの保存試行 (Primary Attempt)
Debug.Print "Attempting Primary Save to: " & targetPath
' ネットワークパスへの書き込みを試みる
' ※注意: SaveAsは図面のパス自体を書き換えるため、
' 既存パスがネットワークの場合、失敗時のハンドリングが極めて重要
ThisDrawing.Save
MsgBox "保存が成功しました。", vbInformation
Exit Sub
ErrorHandler:
' 4. エラーハンドリング (Fallback Strategy)
' ネットワーク切断、書き込み禁止、パスが見つからない等のエラーを捕捉
Debug.Print "Primary Save Failed. Error: " & Err.Number & " - " & Err.Description
' ローカルへの退避パスを生成 (例: FileName_20231027_123045.dwg)
localPath = LOCAL_CACHE_DIR & Replace(fileName, ".dwg", "") & "_" & serialNo & ".dwg"
Debug.Print "Initiating Shadow-Save to: " & localPath
' 重要: ネットワークへの書き込みが中途半端に失敗している可能性があるため、
' 完全に独立した「ローカル保存」を強制する
On Error Resume Next
ThisDrawing.SaveAs localPath
If Err.Number = 0 Then
MsgBox "【警告】ネットワーク接続エラーを検知しました。" & vbCrLf & _
"図面はローカルキャッシュへ安全に退避されました。" & vbCrLf & _
"次回起動時に同期が必要です。", vbExclamation, "Shadow-Save Executed"
Else
MsgBox "【致命的エラー】ローカルへの退避にも失敗しました!" & vbCrLf & _
"作業内容をコピーしてメモ帳等に控えてください。", vbCritical, "System Failure"
End If
On Error GoTo 0
End Sub
''' <summary>
''' 起動時に実行される復旧同期チェック
''' </summary>
Public Sub CheckForShadowFiles()
Dim fso As New FileSystemObject
Dim folder As folder
Dim file As file
Dim localPath As String
Dim serverPath As String
' 本来は現在の図面の本来の場所を特定するロジックが必要
' ここでは概念的な実装を示す
Set folder = fso.GetFolder(LOCAL_CACHE_DIR)
For Each file In folder.Files
If fso.GetExtensionName(file.Path) = "dwg" Then
' ここでサーバー側のファイルと、ローカルのシャドウファイルを比較する
' タイムスタンプ、あるいは独自のメタデータ(XML等)を用いた比較を推奨
Debug.Print "Found Shadow File: " & file.Path
' ユーザーに同期を促すダイアログを表示
If MsgBox("未同期のローカルキャッシュが見つかりました:" & vbCrLf & _
file.Name & vbCrLf & _
"サーバー側へ同期(上書き)しますか?", vbYesNo + vbQuestion) = vbYes Then
' 同期ロジック(ファイルコピー)をここに実装
' SyncToServer file.Path, serverPath
End If
End If
Next file
End Sub
4. プロフェッショナルが留意すべき「極限の注意点」
このシステムをプロダクション環境に投入する際、以下の3点を決して忘れてはならない。
① ファイルロックのデッドロック
ネットワークエラーが発生した際、OS側で「ファイルがまだ書き込み中である」と誤認され、ロックが残り続けることがある。`FileSystemObject` を使用して、保存前に `file.IsReady` や `file.Attributes` を確認するロジックを組み込むことで、不適切な上書きを回避できる。
② メタデータの同期
単にDWGファイルをコピーするだけでは不十分だ。もしツールが「どの図面の、どのステップまで処理が終わったか」を外部DB(SQL ServerやAccess)に記録しているなら、「DWGの保存成功」と「DBの更新」は一つのトランザクションとして扱うべきだ。
DWGをローカルに退避させたなら、その「退避した事実」と「対象のID」をログファイル(JSONやXML)としてローカルに書き出しておく。これが復旧時の「地図」になる。
③ ローカルディレクトリの管理(ガベージコレクション)
ローカルに退避ファイルを溜め込み続けるのは、設計として美しくない。
「同期が完了したファイル」および「作成から30日以上経過した古いキャッシュ」を自動的に削除するクリーンアップ・ロジックを必ず実装せよ。これを怠ると、クライアントのPCのディスク容量を圧迫し、別のクレームを招くことになる。
結びに代えて
自動化エンジニアの真価は、順調な時にどれだけ速いコードを書けるかではなく、最悪の事態が起きた時に、どれだけ優雅に、かつ確実にデータを守り抜けるかで決まる。
「ネットワークは切れるもの」という前提に立ち、設計の最初の一行から「失敗した時のフォールバック」を組み込む。この思考こそが、アマチュアとプロフェッショナルを分かつ境界線である。
