一、集中化服务器模式的架构概览

1.1 什么是集中化服务器模式

在Blue Prism的数字工人(Digital Worker)架构里,集中化服务器模式是最常见的部署方式。说白了,就是把所有的流程执行能力集中放在少数几台高性能服务器上,而不是每个业务人员自己的电脑上都跑。这样做的目的是统一管理、统一监控、统一调度。

但这个模式也有它的代价——一旦这些集中的服务器出了问题,比如流程执行异常、数字工人掉线、会话资源耗尽,影响面就非常大。所以排查这类问题,是我们日常运维中最头疼的事情之一。

1.2 常见架构拓扑

在实际项目中,集中化服务器模式通常分为三层:管理控制台层负责流程设计和调度配置,执行服务器层部署数字工人并负责流程的实际执行,数据存储层则保存流程运行状态、日志和会话信息。

下面用一个脚本来检查集中化服务器环境的基本状态:

# ============================================================
# 技术栈:PowerShell + Blue Prism REST API + Windows Server
# 用途:检查Blue Prism集中化服务器环境的基本健康状态
# ============================================================

# 定义Blue Prism服务地址
$bpServer = "https://bp-server.company.com"
$bpUser = "admin"
$bpPassword = ConvertTo-SecureString "P@ssw0rd123" -AsPlainText -Force

# 构造认证凭据
$credential = New-Object System.Net.NetworkCredential($bpUser, $bpPassword)

# 设置请求头,包含认证信息
$headers = @{
    "Accept" = "application/json"
    "Authorization" = "Basic " + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$bpUser:$bpPassword"))
}

# 请求数字工人列表,获取所有工人的运行状态
$response = Invoke-RestMethod -Uri "$bpServer/automation/api/v3/workers" -Headers $headers -Method Get

# 遍历输出每个数字工人的详细信息
foreach ($worker in $response) {
    Write-Host "================================================"
    Write-Host "数字工人名称: $($worker.name)"
    Write-Host "当前状态: $($worker.status)"
    Write-Host "已运行时间: $($worker.uptime)"
    Write-Host "当前负载: $($worker.loadLevel)%"
    Write-Host "================================================"
}

# 统计异常状态的数量,便于快速定位问题范围
$offlineWorkers = $response | Where-Object { $_.status -eq "Offline" }
$highLoadWorkers = $response | Where-Object { $_.loadLevel -gt 80 }

Write-Host ""
Write-Host "异常统计:" -ForegroundColor Yellow
Write-Host "离线数字工人数量: $($offlineWorkers.Count)"
Write-Host "高负载数字工人数量: $($highLoadWorkers.Count)"

二、流程运行异常的常见表现

2.1 数字工人状态异常

数字工人状态异常是最直观的故障表现。你在管理控制台上看,数字工人应该显示为"Online"状态,但如果它变成"Offline"或者频繁在"Online"和"Busy"之间切换,那基本就是出了问题。

常见的状态异常有以下几种情况:突然掉线,即数字工人本来在运行,突然变成Offline;假在线,显示Online但实际无法接收新任务;状态震荡,短时间内反复切换Online和Offline。这三种情况的出现频率和持续时间往往能帮我们判断问题的严重程度。

2.2 流程执行卡顿或中断

流程在执行过程中突然卡住,或者执行到某个步骤就停了,不再往下走。这种情况特别烦人,因为你从表面上看,数字工人还在Online状态,流程也在Running状态,但实际上已经没有任何进展了。

更麻烦的是,有些流程卡住时不会报错,监控面板上也看不到任何异常指标,只有业务人员反馈说数据没有及时更新时才能发现问题。这就需要我们有主动巡检的机制。

2.3 会话资源耗尽

这是集中化模式下最常见的问题之一。Blue Prism的会话是有数量限制的,每个数字工人能同时运行的会话数也是有限的。当大量的流程同时调度运行时,会话资源被占满,新的流程就无法获取资源,导致任务堆积或者超时失败。

会话资源耗尽往往发生在业务高峰期,比如月末结账、月初报税这些时间点。很多团队在规划服务器资源时只考虑了日常的业务量,没有给高峰期留出余量。

三、异常排查的核心思路与工具

3.1 监控面板的使用

Blue Prism自带的监控面板(Monitoring Dashboard)是排查异常的第一站。你需要重点关注以下几个指标:

  1. 会话利用率:当前活跃会话数与最大会话数的比值,超过85%就要警惕了
  2. 流程队列长度:等待执行的流程数量,如果队列一直在增长说明处理能力跟不上
  3. 数字工人响应时间:流程步骤之间的平均耗时,响应时间变长意味着可能有资源瓶颈
  4. 错误率:流程执行失败的百分比,超过10%就需要排查原因

下面用一个脚本来自动化检查这些关键指标:

# ============================================================
# 技术栈:PowerShell + Blue Prism REST API + Windows Server
# 用途:自动采集Blue Prism关键监控指标
# ============================================================

$bpServer = "https://bp-server.company.com"
$bpUser = "admin"
$bpPassword = "P@ssw0rd123"

# 设置认证头
$authHeader = "Basic " + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$bpUser:$bpPassword"))
$headers = @{
    "Accept" = "application/json"
    "Authorization" = $authHeader
}

# ---- 1. 获取会话使用率 ----
# 请求所有会话信息,统计活跃会话数
$sessionInfo = Invoke-RestMethod -Uri "$bpServer/automation/api/v3/sessions" -Headers $headers

$totalSessions = ($sessionInfo | Measure-Object).Count
$activeSessions = ($sessionInfo | Where-Object { $_.status -eq "Active" } | Measure-Object).Count
# 假设最大会话数为200,计算利用率
$sessionUtilization = [Math]::Round(($activeSessions / 200) * 100, 2)

Write-Host "会话总数: $totalSessions"
Write-Host "活跃会话数: $activeSessions"
Write-Host "会话利用率: $sessionUtilization%"

# 判断是否超过安全阈值
if ($sessionUtilization -gt 85) {
    Write-Host "警告:会话利用率已超过85%,存在资源耗尽风险!" -ForegroundColor Red
}

# ---- 2. 获取队列长度 ----
# 检查有多少流程在排队等待执行
$queueInfo = Invoke-RestMethod -Uri "$bpServer/automation/api/v3/process-queue" -Headers $headers

$queueLength = ($queueInfo | Measure-Object).Count
Write-Host "当前队列长度: $queueLength"

# ---- 3. 获取错误率 ----
# 查看最近50条流程实例,统计失败数量
$recentProcesses = Invoke-RestMethod -Uri "$bpServer/automation/api/v3/process-instances?limit=50" -Headers $headers

$failedCount = ($recentProcesses | Where-Object { $_.status -eq "Failed" } | Measure-Object).Count
$errorRate = [Math]::Round(($failedCount / 50) * 100, 2)

Write-Host "最近50条流程的失败数: $failedCount"
Write-Host "错误率: $errorRate%"

# ---- 4. 输出综合健康评估 ----
# 根据各项指标计算综合健康评分
Write-Host ""
Write-Host "========== 综合健康评估 ==========" -ForegroundColor Cyan

$healthScore = 100
if ($sessionUtilization -gt 85) { $healthScore -= 30 }
if ($queueLength -gt 100) { $healthScore -= 20 }
if ($errorRate -gt 10) { $healthScore -= 25 }

if ($healthScore -ge 80) {
    Write-Host "系统状态:健康" -ForegroundColor Green
} elseif ($healthScore -ge 50) {
    Write-Host "系统状态:警告,需要关注" -ForegroundColor Yellow
} else {
    Write-Host "系统状态:异常,需要立即处理!" -ForegroundColor Red
}

Write-Host "健康评分: $healthScore/100"

3.2 日志分析的要点

光看监控面板还不够,很多深层次的问题需要从日志里找答案。Blue Prism的日志分为几类:应用日志记录流程执行过程中的详细信息,服务器日志记录数字工人服务本身的运行状态,错误日志则专门记录异常和错误信息。

在集中化服务器模式下,日志通常会存储在Windows事件日志或者应用程序的专用日志目录中。下面演示如何提取和分析关键的错误日志:

# ============================================================
# 技术栈:PowerShell + Windows Event Log + Blue Prism
# 用途:从Windows事件日志中提取Blue Prism相关的错误信息
# ============================================================

# 获取最近1小时内Blue Prism相关的错误事件
# 注意:需要以管理员身份运行
$since = (Get-Date).AddHours(-1)

# 查询应用程序日志中的错误
# Level 2代表Error级别,通过ProviderName筛选Blue Prism相关来源
$appErrors = Get-WinEvent -FilterHashtable @{
    LogName    = "Application"
    Level      = 2
    StartTime  = $since
} | Where-Object {
    $_.Message -match "Blue Prism|Process Engine|Session|Worker"
}

Write-Host "最近1小时内发现 $($appErrors.Count) 条错误日志" -ForegroundColor Yellow
Write-Host ""

# 按时间倒序输出,方便快速定位最新的问题
foreach ($event in $appErrors | Sort-Object TimeCreated -Descending | Select-Object -First 10) {
    Write-Host "时间: $($event.TimeCreated)" -ForegroundColor Cyan
    Write-Host "来源: $($event.ProviderName)"
    Write-Host "ID: $($event.Id)"
    Write-Host "消息摘要: $($event.Message.Substring(0, [Math]::Minimum(200, $event.Message.Length)))"
    Write-Host "------------------------------------"
}

# 统计错误类型分布,帮助判断问题的主要来源
Write-Host ""
Write-Host "========== 错误类型分布 ==========" -ForegroundColor Cyan

$appErrors | Group-Object ProviderName | Sort-Object Count -Descending | ForEach-Object {
    Write-Host "$($_.Name): $($_.Count) 条"
}

# 提取特定模式的错误,帮助快速分类问题
$sessionTimeouts = $appErrors | Where-Object { $_.Message -match "timeout|timed out" }
$connFailures = $appErrors | Where-Object { $_.Message -match "connection.*failed|disconnect" }
$resourceErrors = $appErrors | Where-Object { $_.Message -match "out of memory|resource" }

Write-Host ""
Write-Host "会话超时相关错误: $($sessionTimeouts.Count) 条"
Write-Host "连接失败相关错误: $($connFailures.Count) 条"
Write-Host "资源相关错误: $($resourceErrors.Count) 条"

四、典型异常场景的排查实战

4.1 数字工人频繁掉线的排查

场景描述:某企业的数字工人集群中有5台执行服务器,其中3台出现频繁掉线的情况。掉线的时间不固定,每天大约发生3到4次,每次持续5到15分钟后自动恢复。

排查步骤第一步,检查数字工人服务的运行状态:

# ============================================================
# 技术栈:PowerShell + Windows Service Management
# 用途:检查Blue Prism数字工人服务的运行状态
# ============================================================

# 获取Blue Prism相关的服务列表
$bpServices = Get-Service | Where-Object {
    $_.Name -match "BluePrism|ProcessEngine|SessionManager"
}

foreach ($svc in $bpServices) {
    Write-Host "服务名称: $($svc.Name)" -ForegroundColor Cyan
    Write-Host "显示名称: $($svc.DisplayName)"
    Write-Host "当前状态: $($svc.Status)"
    Write-Host "启动类型: $($svc.StartType)"
    Write-Host "最后重启时间: $($svc.Started)"
    Write-Host "------------------------------------"
}

# 通过事件日志查看服务重启记录
# Event ID 7036表示服务启动事件
$serviceRestartEvents = Get-WinEvent -FilterHashtable @{
    LogName   = "System"
    ProviderName = "Service Control Manager"
    Id        = 7036
} -MaxEvents 50 | Where-Object {
    $_.Message -match "BluePrism|ProcessEngine"
}

Write-Host ""
Write-Host "========== 服务重启历史 ==========" -ForegroundColor Cyan

$serviceRestartEvents | Sort-Object TimeCreated -Descending | ForEach-Object {
    Write-Host "时间: $($_.TimeCreated) | 消息: $($_.Message)"
}

第二步,检查系统资源使用情况,看是不是资源不足导致服务崩溃:

# ============================================================
# 技术栈:PowerShell + Windows Performance Counter
# 用途:检查服务器系统资源使用情况
# ============================================================

# 检查CPU使用率
$cpuUsage = (Get-CimInstance Win32_Processor | Measure-Object -Property LoadPercentage -Average).Average
Write-Host "CPU使用率: $cpuUsage%"

# 检查内存使用率
$os = Get-CimInstance Win32_OperatingSystem
$totalMemoryGB = [Math]::Round($os.TotalVisibleMemorySize / 1024 / 1024, 2)
$freeMemoryGB = [Math]::Round($os.FreePhysicalMemory / 1024 / 1024, 2)
$memoryUsedPercent = [Math]::Round((($os.TotalVisibleMemorySize - $os.FreePhysicalMemory) / $os.TotalVisibleMemorySize) * 100, 2)
Write-Host "总内存: ${totalMemoryGB} GB"
Write-Host "空闲内存: ${freeMemoryGB} GB"
Write-Host "内存使用率: ${memoryUsedPercent}%"

# 检查磁盘空间,磁盘满了也会导致服务异常
$diskInfo = Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3"
foreach ($disk in $diskInfo) {
    $totalGB = [Math]::Round($disk.Size / 1GB, 2)
    $freeGB = [Math]::Round($disk.FreeSpace / 1GB, 2)
    $usedPercent = [Math]::Round((($disk.Size - $disk.FreeSpace) / $disk.Size) * 100, 2)
    Write-Host "磁盘 $($disk.DeviceID): 总计 ${totalGB}GB, 空闲 ${freeGB}GB, 使用率 ${usedPercent}%"
}

# 检查网络连通性,确保能访问数据库等依赖服务
Write-Host ""
Write-Host "========== 网络连通性检查 ==========" -ForegroundColor Cyan
Test-Connection -ComputerName "bp-db-server.company.com" -Count 4

第三步,检查进程级别的资源占用,判断是否存在内存泄漏:

# ============================================================
# 技术栈:PowerShell + Performance Counter
# 用途:检查Blue Prism相关进程的资源占用
# ============================================================

# 查找Blue Prism相关的进程
$bpProcesses = Get-Process | Where-Object {
    $_.Name -match "ProcessEngine|SessionManager|BluePrism"
}

foreach ($proc in $bpProcesses) {
    Write-Host "进程: $($proc.Name)" -ForegroundColor Cyan
    Write-Host "PID: $($proc.Id)"
    Write-Host "内存(MB): $([Math]::Round($proc.WorkingSet64 / 1MB, 2))"
    Write-Host "启动时间: $($proc.StartTime)"
    Write-Host "线程数: $($proc.Threads.Count)"
    Write-Host "------------------------------------"
}

# 检查是否有进程内存泄漏的迹象
# 通过间隔采样对比内存变化趋势
$memorySamples = @()

Write-Host ""
Write-Host "监控Blue Prism进程内存变化(30秒采样)..." -ForegroundColor Yellow

for ($i = 1; $i -le 3; $i++) {
    $currentMemory = ($bpProcesses | Measure-Object -Property WorkingSet64 -Sum).Sum
    $memorySamples += [PSCustomObject]@{
        SampleTime = Get-Date
        TotalMemoryMB = [Math]::Round($currentMemory / 1MB, 2)
    }
    Start-Sleep -Seconds 10
}

Write-Host ""
$memorySamples | Format-Table -AutoSize

4.2 流程执行到某一步骤卡死的排查

场景描述:某个财务流程在执行到"数据验证"步骤时卡住,既不报错也不继续往下走,已经卡了两个小时。

这种情况通常是以下几种原因导致的:该步骤调用的外部系统接口超时,步骤中的逻辑存在死循环,或者步骤依赖的某个服务挂了。

# ============================================================
# 技术栈:PowerShell + Blue Prism REST API
# 用途:定位流程执行卡死的具体步骤
# ============================================================

$bpServer = "https://bp-server.company.com"
$bpUser = "admin"
$bpPassword = "P@ssw0rd123"

$authHeader = "Basic " + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$bpUser:$bpPassword"))
$headers = @{
    "Accept" = "application/json"
    "Authorization" = $authHeader
}

# 获取当前所有正在运行的流程实例
$runningProcesses = Invoke-RestMethod -Uri "$bpServer/automation/api/v3/process-instances?status=Running" -Headers $headers

Write-Host "当前正在运行的流程实例数: $($runningProcesses.Count)" -ForegroundColor Cyan

# 检查每个流程的运行时长,标记疑似卡死的流程
$now = Get-Date
foreach ($proc in $runningProcesses) {
    $startTime = [DateTime]::Parse($proc.startTime)
    $duration = $now - $startTime
    
    # 运行超过30分钟视为疑似卡死
    $isStuck = $duration.TotalMinutes -gt 30
    
    Write-Host ""
    Write-Host "流程: $($proc.name)" -ForegroundColor $(if ($isStuck) { "Red" } else { "Green" })
    Write-Host "实例ID: $($proc.id)"
    Write-Host "开始时间: $($startTime)"
    Write-Host "已运行: $($duration.ToString())"
    
    if ($isStuck) {
        Write-Host "警告:此流程运行超过30分钟,疑似卡死!" -ForegroundColor Red
        
        # 获取该流程的详细步骤信息
        $stepDetails = Invoke-RestMethod -Uri "$bpServer/automation/api/v3/process-instances/$($proc.id)/steps" -Headers $headers
        
        Write-Host "当前执行步骤: $($stepDetails.currentStepName)"
        Write-Host "步骤状态: $($stepDetails.currentStepStatus)"
        Write-Host "步骤开始时间: $($stepDetails.currentStepStartTime)"
        
        # 计算步骤已执行的时长
        $stepDuration = $now - [DateTime]::Parse($stepDetails.currentStepStartTime)
        Write-Host "步骤已执行: $($stepDuration.ToString())"
        
        # 如果步骤执行时间异常长,获取更详细的日志
        if ($stepDuration.TotalMinutes -gt 10) {
            Write-Host "步骤执行时间异常,正在获取详细日志..." -ForegroundColor Yellow
            $stepLogs = Invoke-RestMethod -Uri "$bpServer/automation/api/v3/process-instances/$($proc.id)/logs?limit=20" -Headers $headers
            Write-Host "最近日志条目:" -ForegroundColor Cyan
            $stepLogs | Select-Object -Last 5 | ForEach-Object {
                Write-Host "  [$($_.timestamp)] $($_.message)"
            }
        }
    }
}

4.3 并发资源冲突导致流程失败的排查

场景描述:每到月底结账高峰期,大量财务流程同时调度,导致会话资源被迅速耗尽,部分流程直接报错失败。

# ============================================================
# 技术栈:PowerShell + Blue Prism REST API + SQL
# 用途:排查并发资源冲突问题
# ============================================================

$bpServer = "https://bp-server.company.com"
$bpUser = "admin"
$bpPassword = "P@ssw0rd123"

$authHeader = "Basic " + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$bpUser:$bpPassword"))
$headers = @{
    "Accept" = "application/json"
    "Authorization" = $authHeader
}

# ---- 1. 分析并发模式 ----
Write-Host "========== 并发模式分析 ==========" -ForegroundColor Cyan

$schedulers = Invoke-RestMethod -Uri "$bpServer/automation/api/v3/schedulers" -Headers $headers

foreach ($sched in $schedulers) {
    Write-Host ""
    Write-Host "调度器: $($sched.name)" -ForegroundColor Yellow
    Write-Host "状态: $($sched.status)"
    Write-Host "最大并发数: $($sched.maxConcurrency)"
    Write-Host "当前活跃流程数: $($sched.activeProcesses)"
    Write-Host "排队等待数: $($sched.queuedProcesses)"
    
    # 计算并发压力指数,越接近1说明越接近资源极限
    $pressureIndex = [Math]::Round(($sched.activeProcesses + $sched.queuedProcesses) / $sched.maxConcurrency, 2)
    Write-Host "并发压力指数: $pressureIndex"
    
    if ($pressureIndex -gt 0.9) {
        Write-Host "警告:并发压力过高,即将超出容量限制!" -ForegroundColor Red
    }
}

# ---- 2. 分析资源竞争 ----
Write-Host ""
Write-Host "========== 资源竞争分析 ==========" -ForegroundColor Cyan

$processSessions = Invoke-RestMethod -Uri "$bpServer/automation/api/v3/process-sessions" -Headers $headers

# 按流程名称分组统计会话占用
$sessionByProcess = $processSessions | Group-Object processName | Sort-Object Count -Descending

Write-Host "各流程的会话占用情况:"
foreach ($group in $sessionByProcess) {
    $percent = [Math]::Round(($group.Count / $processSessions.Count) * 100, 2)
    Write-Host "  $($group.Name): $($group.Count) 个会话 ($percent%)"
}

# ---- 3. 使用SQL查询数据库中的历史数据 ----
Write-Host ""
Write-Host "========== 历史并发数据分析 ==========" -ForegroundColor Cyan

$sqlQuery = @"
SELECT 
    DATE(created_time) AS [执行日期],
    COUNT(*) AS [流程执行总数],
    SUM(CASE WHEN status = 'Failed' THEN 1 ELSE 0 END) AS [失败数],
    ROUND(
        SUM(CASE WHEN status = 'Failed' THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2
    ) AS [失败率]
FROM process_instances
WHERE created_time >= DATEADD(DAY, -7, GETDATE())
GROUP BY DATE(created_time)
ORDER BY [执行日期] DESC;
"@

Write-Host "SQL查询语句:" -ForegroundColor Gray
Write-Host $sqlQuery

# 连接数据库执行查询
$connectionString = "Server=bp-db-server;Database=blueprism;User Id=report_reader;Password=R3adOnly!"
$dataAdapter = New-Object System.Data.SqlClient.SqlDataAdapter($sqlQuery, $connectionString)
$dataTable = New-Object System.Data.DataTable
$dataAdapter.Fill($dataTable)

$dataTable | Format-Table -AutoSize

# ---- 4. 生成优化建议 ----
Write-Host ""
Write-Host "========== 优化建议 ==========" -ForegroundColor Green

$recommendations = @()

# 检查是否所有流程都使用默认调度策略
$defaultSchedulerCount = ($processSessions | Where-Object { $_.schedulerName -eq "Default" }).Count
$defaultPercent = [Math]::Round(($defaultSchedulerCount / $processSessions.Count) * 100, 2)

if ($defaultPercent -gt 70) {
    $recommendations += "大量流程使用默认调度器,建议按业务优先级拆分调度器"
}

# 检查是否有流程的并发配置过高
$highConcurrencyProcesses = $schedulers | Where-Object { $_.maxConcurrency -gt 50 }
if ($highConcurrencyProcesses.Count -gt 0) {
    $recommendations += "存在高并发配置的调度器,建议评估是否合理"
}

# 检查总资源利用率
$totalActive = ($schedulers | Measure-Object -Property activeProcesses -Sum).Sum
$totalMax = ($schedulers | Measure-Object -Property maxConcurrency -Sum).Sum
$utilizationRate = [Math]::Round(($totalActive / $totalMax) * 100, 2)

if ($utilizationRate -gt 90) {
    $recommendations += "总并发利用率已超过90%,建议增加数字工人数量或优化流程执行效率"
}

if ($recommendations.Count -eq 0) {
    $recommendations += "当前配置基本合理,建议持续监控并定期优化"
}

$recommendations | ForEach-Object { Write-Host "  $_" }

五、应用场景分析

5.1 企业级批量流程调度

在大型企业里,集中化服务器模式最常见的应用场景就是批量流程调度。比如一家银行每天要处理几十万笔交易,每笔交易都需要经过多个流程步骤——身份验证、风控检查、资金划转、对账确认。这些流程不可能让每个人在自己的电脑上跑,必须集中到服务器上统一调度。

这种情况下,异常排查的重点在于:当批量任务出现大面积失败时,如何快速判断是流程本身的问题还是平台层面的问题。如果几十个流程同时失败,大概率是平台层面的问题,比如数据库连接池满了、会话资源不够用了,而不是某个具体流程的代码写错了。

5.2 金融行业的自动交易处理

金融行业对流程执行的稳定性要求极高。一个交易流程如果执行失败,可能导致资金损失或者合规风险。在这种场景下,集中化服务器的异常排查不仅是一个技术问题,更是一个业务连续性保障问题。

很多金融机构会采用双活架构——两套集中化服务器集群互为备份,一套出问题后另一套可以立即接管。但这带来了一个新的挑战:排查问题时需要考虑两套系统之间的状态同步问题。

5.3 跨国企业的分布式部署

还有一种特殊场景是跨国企业的分布式部署。比如一家公司在亚太、欧洲、美洲都有业务,每个区域有自己的Blue Prism服务器集群。流程调度需要在跨区域进行,这时候网络延迟和时区差异都会成为影响流程执行的因素。

在这种场景下,排查异常时特别要注意时间戳的一致性。如果亚太区的流程在凌晨调度,但欧洲的服务器日志显示的是不同的时区,可能导致时间线对不上,排查起来非常费劲。

六、技术优缺点分析

6.1 集中化模式的优势

集中化服务器模式的优势主要有三个:

第一是管理效率高。所有数字工人集中在一台或几台服务器上,运维人员只需要关注少数几台机器,不用满公司跑着排查问题。

第二是资源利用率高。把流程执行任务集中到服务器上,可以充分利用服务器的计算能力,而不是分散在各个业务人员的电脑上。

第三是安全可控。集中化部署意味着可以统一配置安全策略、统一进行权限管控,不会出现某个业务人员自己的电脑被黑客攻击导致流程执行环境被入侵的情况。

6.2 集中化模式的局限

集中化模式的局限性也很明显:

第一是单点故障风险。如果集中的服务器宕机了,所有流程都会受到影响。这也是为什么建议至少部署两台执行服务器做负载均衡。

第二是扩展性受限。当业务量增长时,可能需要增加更多的执行服务器,这时候涉及到集群配置、负载均衡、数据同步等一系列复杂问题。

第三是调试难度大。集中化模式下,多个流程同时在一台服务器上运行,当出现问题时,很难快速判断是哪个流程导致了问题。日志混杂在一起,排查起来非常费劲。

七、注意事项与最佳实践

7.1 资源规划与容量管理

在做集中化服务器规划时,一定要留足余量。一般建议服务器的CPU使用率不要超过70%,内存使用率不要超过80%,磁盘空间保留至少20%的余量。

还有一个很重要的点是会话数的规划。Blue Prism的会话是有成本的——每个活跃会话都会占用数据库连接和服务器资源。如果一个调度器配置了100个并发,意味着你需要确保服务器能同时处理100个会话。

7.2 监控告警体系搭建

不要等到出了问题再去排查,应该建立完善的监控告警体系。下面是一个基于PowerShell的监控告警脚本示例,可以设置定时任务定期执行:

# ============================================================
# 技术栈:PowerShell + Windows Task Scheduler + SMTP
# 用途:搭建Blue Prism监控告警体系
# ============================================================

$bpServer = "https://bp-server.company.com"
$bpUser = "admin"
$bpPassword = "P@ssw0rd123"
$emailTo = "it-alerts@company.com"
$emailFrom = "bp-monitor@company.com"
$smtpServer = "smtp.company.com"

$authHeader = "Basic " + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$bpUser:$bpPassword"))
$headers = @{
    "Accept" = "application/json"
    "Authorization" = $authHeader
}

$alertMessages = @()

# ---- 检查1:数字工人在线状态 ----
$workers = Invoke-RestMethod -Uri "$bpServer/automation/api/v3/workers" -Headers $headers
$offlineCount = ($workers | Where-Object { $_.status -eq "Offline" }).Count
$totalWorkers = $workers.Count

if ($offlineCount -gt 0) {
    $alertMessages += "数字工人离线告警:$offlineCount / $totalWorkers 个数字工人处于离线状态"
}

# ---- 检查2:会话利用率 ----
$sessions = Invoke-RestMethod -Uri "$bpServer/automation/api/v3/sessions" -Headers $headers
$activeSessions = ($sessions | Where-Object { $_.status -eq "Active" }).Count
$sessionUtilization = [Math]::Round(($activeSessions / 200) * 100, 2)

if ($sessionUtilization -gt 85) {
    $alertMessages += "会话资源告警:活跃会话数 $activeSessions,利用率 ${sessionUtilization}%,超过85%阈值"
}

# ---- 检查3:流程队列积压 ----
$queue = Invoke-RestMethod -Uri "$bpServer/automation/api/v3/process-queue" -Headers $headers
$queueLength = ($queue | Measure-Object).Count

if ($queueLength -gt 200) {
    $alertMessages += "队列积压告警:当前队列长度 $queueLength,超过200的阈值"
}

# ---- 检查4:错误率 ----
$recentInstances = Invoke-RestMethod -Uri "$bpServer/automation/api/v3/process-instances?limit=100" -Headers $headers
$failedCount = ($recentInstances | Where-Object { $_.status -eq "Failed" } | Measure-Object).Count
$errorRate = [Math]::Round(($failedCount / 100) * 100, 2)

if ($errorRate -gt 15) {
    $alertMessages += "错误率告警:最近100个流程中 $failedCount 个失败,错误率 ${errorRate}%"
}

# ---- 发送告警邮件 ----
if ($alertMessages.Count -gt 0) {
    $emailBody = "Blue Prism 监控告警`n" + 
                 "告警时间: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')`n" +
                 "服务器: $bpServer`n" +
                 "----------------------------------------`n" +
                 ($alertMessages -join "`n")
    
    try {
        Send-MailMessage -To $emailTo -From $emailFrom -Subject "Blue Prism 监控告警 - $($alertMessages.Count) 项异常" `
            -Body $emailBody -SmtpServer $smtpServer -Priority High
        Write-Host "告警邮件已发送至 $emailTo" -ForegroundColor Green
    } catch {
        Write-Host "告警邮件发送失败: $_" -ForegroundColor Red
        # 邮件发送失败时,写入本地日志文件作为备选
        $logFile = "C:\Logs\bp-alert-fallback.txt"
        $emailBody | Add-Content -Path $logFile
        Write-Host "告警信息已写入本地日志: $logFile" -ForegroundColor Yellow
    }
} else {
    Write-Host "所有监控指标正常,无需告警" -ForegroundColor Green
}

7.3 日志轮转与归档

集中化服务器上的日志会不断增长,如果不及时处理,可能会导致磁盘空间不足,进而引发更多问题。建议设置日志轮转策略:应用日志保留最近30天,错误日志保留最近90天,归档日志压缩存储保留12个月。

# ============================================================
# 技术栈:PowerShell + Windows Task Scheduler
# 用途:Blue Prism日志轮转与归档
# ============================================================

$logPath = "C:\BluePrism\Logs"
$archivePath = "C:\BluePrism\Logs\Archive"
$retentionDays = 30

# 创建归档目录(如果不存在)
if (-not (Test-Path $archivePath)) {
    New-Item -Path $archivePath -ItemType Directory -Force | Out-Null
}

# 获取超过保留期限的日志文件
$expireDate = (Get-Date).AddDays(-$retentionDays)
$oldLogs = Get-ChildItem -Path $logPath -File -Recurse | Where-Object {
    $_.LastWriteTime -lt $expireDate -and $_.Extension -in ".log", ".txt"
}

Write-Host "发现 $($oldLogs.Count) 个超过 $retentionDays 天的日志文件"

foreach ($logFile in $oldLogs) {
    # 压缩归档
    $archiveName = "$($logFile.BaseName)_$(Get-Date -Format 'yyyyMMdd_HHmmss').zip"
    $archivePathFull = Join-Path $archivePath $archiveName
    
    try {
        Compress-Archive -Path $logFile.FullName -DestinationPath $archivePathFull -Force
        Write-Host "已归档: $($logFile.Name) -> $archiveName" -ForegroundColor Green
        
        # 删除原始文件以释放空间
        Remove-Item -Path $logFile.FullName -Force
    } catch {
        Write-Host "归档失败: $($logFile.Name) - 错误: $_" -ForegroundColor Red
    }
}

# 清理超过12个月的归档文件
$archiveExpireDate = (Get-Date).AddDays(-365)
$oldArchives = Get-ChildItem -Path $archivePath -File | Where-Object {
    $_.LastWriteTime -lt $archiveExpireDate
}

$freedSpaceMB = [Math]::Round(($oldArchives | Measure-Object -Property Length -Sum).Sum / 1MB, 2)
if ($oldArchives.Count -gt 0) {
    $oldArchives | Remove-Item -Force
    Write-Host "已清理 $($oldArchives.Count) 个过期归档,释放 ${freedSpaceMB} MB 空间" -ForegroundColor Yellow
}

7.4 定期健康巡检

建议每周进行一次全面的健康巡检,检查内容包括服务器资源、数字工人状态、流程执行效率、数据库连接池使用情况等。巡检发现的问题要及时记录并跟踪处理。

八、文章总结

集中化服务器模式下的Blue Prism流程运行异常排查,本质上是在一个共享环境里定位问题源头的过程。因为多个流程在同一台服务器上运行,异常可能是平台层面的(比如资源不足、服务崩溃),也可能是某个特定流程层面的(比如代码逻辑错误、外部接口异常)。

排查的核心思路可以总结为三步:

第一步,看整体——先看监控面板和系统资源,判断是平台层面的问题还是单个流程的问题。如果CPU、内存、磁盘、网络都正常,那大概率是单个流程的问题。

第二步,缩小范围——通过数字工人的状态、流程的队列长度、会话的利用率等信息,缩小问题范围。比如如果某个数字工人频繁掉线,那就重点排查这台机器的问题。

第三步,深入细节——查看具体的流程日志和步骤信息,定位到具体的异常步骤。通过Blue Prism的REST API获取流程实例的详细步骤信息,可以快速找到卡在哪一步、什么时候开始异常的。

在日常运维中,最需要做的是预防而不是救火。建立完善的监控告警体系、合理规划资源容量、定期清理日志和归档数据,这些基础工作做好了,异常排查的难度会大幅降低。

最后说一句,Blue Prism的版本更新可能会改变一些API的路径和行为,上面示例中的API接口可能需要根据实际使用的版本进行调整。建议在使用前先查阅对应版本的官方文档,确认接口的准确性。