【上級プロフェッショナル向け】ネットワーク切断時のRPCサーバー不可エラー(0x800706BA)に対するFSO再接続&自動自己復旧
開発プロジェクトで最も頭を悩ませる問題の一つが、「不安定なネットワーク環境に起因するI/Oエラー」だ。
特に、VBScriptによるファイルシステムオブジェクト(FSO: `Scripting.FileSystemObject`)を用いて、NASや共有フォルダ(UNCパス)上のファイルを継続的に監視・操作するバッチ処理を組んでいる現場では、一時的なLANの瞬断やVPNの揺らぎが命取りになる。
何も対策を講じていないコードは、容赦なく以下の致命的なエラーを吐いてクラッシュする。
> エラー: 0x800706BA
> 説明: RPC サーバーを利用できません。 (The RPC server is unavailable.)
このエラーに直面したとき、未熟なプログラマーは「ネットワークが悪いから仕方ない」と諦め、タスクスケジューラでのリトライ設定や、場当たり的な `On Error Resume Next` による握りつぶしに走る。だが、それはプロの仕事ではない。
今回は、FSOの背後にあるCOM/RPCのライフサイクルを深く理解し、ネットワークの切断を検知した瞬間から自動的に回線を再確立して処理を自己復旧させる、プロダクション品質の堅牢なコードを伝授しよう。
—
なぜ通常のFSOコードではネットワーク切断に太刀打ちできないのか?
多くのエンジニアは、FSOを以下のようにインスタンス化して使い回している。
‘ 【アンチパターン】スクリプト開始時に1度だけ生成し、グローバルに使い回す
Set fso = CreateObject(“Scripting.FileSystemObject”)
Sub ProcessFile()
‘ ネットワーク上のファイルを操作
fso.CopyFile “\\server\share\data.csv”, “C:\Local\”
End Sub
この設計の何が問題か?
`Scripting.FileSystemObject` は、生成された瞬間にOSのファイルシステムドライバやネットワークプロバイダとのセッションを内部キャッシュすることがある。そのため、一度RPCサーバー不可(0x800706BA)などの致命的な通信断が発生すると、FSOオブジェクト自体の内部ステートが破損(ゾンビ化)する。
この状態でいくらメソッドを叩き直しても、FSOは死んだセッションにしがみつき続け、永遠にエラーを吐き出し続けるのだ。
堅牢なアーキテクチャの要件
真に耐障害性の高いシステムを構築するためには、以下の3原則を徹底する必要がある。
1. FSOインスタンスの「使い捨て(Disposable)」化
エラーが発生した際、あるいは定期的なインターバルごとに、既存のFSOインスタンスを完全に破棄(`Nothing`代入)し、メモリ空間からパージする。
2. 指数バックオフ(Exponential Backoff)アルゴリズムの採用
ネットワーク復旧直後にリクエストが集中してサーバーを圧迫するのを防ぐため、再試行の間隔を段階的に広げる(例:2秒、4秒、8秒…)。
3. 存在確認(Probe)による死活監視
ファイル操作の前に、親フォルダへのアクセスや `FolderExists` などの軽量なプローブを実行し、回線が生きていることを担保してから本命のI/Oを走らせる。
—
【プロダクションコード】自己復旧型FSOラッパーの実装
現場でそのままコピペして利用できる、最高峰の堅牢性を持ったVBScriptコードを公開する。このスクリプトは、ネットワーク共有フォルダ上のファイル操作において、RPCエラーが発生しても自動でコネクションを再構築し、処理を完遂する。
Option Explicit
‘ ==============================================================================
‘ スクリプト名: RobustFSOManager.vbs
‘ 概要: ネットワーク切断(0x800706BA等)を自動検知・自己復旧するFSOラッパー
‘ ターゲット: 安定稼働が求められる業務自動化バッチ
‘ ==============================================================================
‘ メイン処理の実行
Call Main()
Sub Main()
Dim targetPath, destPath
targetPath = “\\192.168.1.100\shared\import\target.csv”
destPath = “C:\LocalData\target.csv”
WScript.Echo “=== ネットワーク耐性型ファイルコピー処理を開始します ===”
‘ 自己復旧型コピー関数を呼び出し(最大リトライ回数: 5回)
If RobustCopyFile(targetPath, destPath, 5) Then
WScript.Echo “[SUCCESS] ファイルの転送と処理が正常に完了しました。”
Else
WScript.Echo “[CRITICAL] 最大リトライ回数を超過しました。処理を中断します。”
End If
End Sub
‘ ——————————————————————————
‘ 堅牢なファイルコピー関数(自動リトライ・FSO再生成ロジック内蔵)
‘ ——————————————————————————
Function RobustCopyFile(ByVal src, ByVal dest, ByVal maxRetries)
Dim fso, attempt, waitTime, success
success = False
attempt = 0
waitTime = 2000 ‘ 初期ウェイト: 2秒 (ミリ秒)
Do While attempt < maxRetries And Not success
attempt = attempt + 1
' 1. FSOインスタンスのクリーン生成(ゾンビ化対策)
On Error Resume Next
Set fso = CreateObject("Scripting.FileSystemObject")
If Err.Number <> 0 Then
WScript.Echo “[WARNING] FSOの生成に失敗しました。Error: ” & Hex(Err.Number) & ” – ” & Err.Description
Err.Clear
Else
‘ 2. ネットワーク経由でのファイル存在確認(プローブ)
Dim parentDir
parentDir = fso.GetParentFolderName(src)
If fso.FolderExists(parentDir) Then
‘ 3. 本命のファイルコピー実行
fso.CopyFile src, dest, True
If Err.Number = 0 Then
success = True
Else
‘ RPCサーバー不可エラー(0x800706BA)やその他のI/Oエラーを捕捉
WScript.Echo “[WARNING] 試行 ” & attempt & “回目: I/Oエラー発生 (Error: ” & Hex(Err.Number) & ” ” & Err.Description & “)”
Err.Clear
End If
Else
WScript.Echo “[WARNING] 試行 ” & attempt & “回目: ネットワークパスに到達できません (FolderExists returned false)”
End If
End If
‘ 4. 失敗時のクリーンアップとバックオフ待機
Set fso = Nothing
If Not success Then
If attempt >= maxRetries Then Exit Do
WScript.Echo “[INFO] ” & (waitTime / 1000) & “秒後に再接続を試行します…”
WScript.Sleep waitTime
‘ 指数バックオフ(待機時間を倍増させる: 最大30秒程度まで)
waitTime = waitTime 2
If waitTime > 30000 Then waitTime = 30000
End If
On Error GoTo 0
Loop
RobustCopyFile = success
End Function
—
コードの設計思想とプロの技術的解説
1. 毎ループごとの `CreateObject` と `Set fso = Nothing`
「毎回インスタンスを生成・破棄するのはパフォーマンス的に非効率ではないか?」という疑問を持つかもしれない。
しかし、数秒〜数分に1回行われるバッチ処理において、COMオブジェクトの生成コスト(数ミリ秒)など誤差に過ぎない。それよりも、「ネットワークが復旧した瞬間に、古い壊れたセッションを引きずらないこと」のメリットの方が圧倒的に大きい。この「使い捨ての哲学」がシステムを不壊にする。
2. `FolderExists` による事前プローブ(死活監視)
いきなり `CopyFile` を実行すると、ファイルロックやOSレベルのタイムアウトによってスクリプト全体が長い間フリーズすることがある。
親フォルダに対して `FolderExists` を挟むことで、OSのネットワークスタック経由で迅速に「現在サーバーと疎通ができるか」をハンドシェイクし、無駄なI/O例外の発生を防ぐ。
3. 指数バックオフ(Exponential Backoff)
ネットワークが瞬断した直後は、サーバー側も復旧処理の真っ最中である可能性が高い。そこに高頻度でリクエストを投げ続ける(リトライの嵐)と、かえって回復を遅らせる原因になる。
`waitTime = waitTime 2` によって、待機時間を `2秒 -> 4秒 -> 8秒 -> 16秒 -> 30秒` と引き延ばすことで、ネットワークインフラに優しい自己復旧を実現している。
—
運用上の注意点とさらなる高みへ
このコードを実際のエンタープライズ環境に投入する際は、以下の点に留意してほしい。
- ログ出力の外部化
プロダクション環境では `WScript.Echo` ではなく、Windowsイベントログや、日付ごとのテキストファイルへエラー詳細(タイムスタンプ付き)を書き出すロガー関数を必ず統合すること。
- UNCパスの記法
ネットワークパスを指定する際は、スラッシュのミスや、DNS解決の不安定さを排除するため、可能な限りIPアドレス(例: `\\192.168.x.x\…`)を使用するか、事前に信頼性の高い名前解決が行われていることを確認すること。
総括
VBScriptはレガシーな言語と揶揄されることもあるが、その内部挙動(COMコンポーネントのライフサイクルとOSのI/Oバインド)の本質を理解していれば、現代の不安定なインフラ環境下でも驚異的なまでの堅牢性を発揮させることができる。
「エラーが起きたら落ちる」システムから、「エラーを織り込み済みで、自律的に治癒する」システムへ。
この記事を手にしたあなたなら、もう不意の `0x800706BA` に怯える必要はない。現場のインフラストラクチャを、あなたの手で真にプロフェッショナルなものに仕立て上げてほしい。
