1+ param (
2+ [Parameter (Mandatory = $true )]
3+ [string ]$BaseUrl ,
4+
5+ [Parameter ]
6+ [string ]$Username ,
7+
8+ [Parameter ]
9+ [string ]$Password ,
10+
11+ [string ]$LogDirectory = " C:\home\txnproc\trace" ,
12+ [int ]$LogRetentionDays = 7
13+ )
14+
15+ # =========================
16+ # Logging setup
17+ # =========================
18+ if (-not (Test-Path $LogDirectory )) {
19+ New-Item - ItemType Directory - Path $LogDirectory - Force | Out-Null
20+ }
21+
22+ function Get-LogFilePath {
23+ $date = (Get-Date ).ToString(" yyyy-MM-dd" )
24+ Join-Path $LogDirectory " ReplayParkedSubscriptions-$date .log"
25+ }
26+
27+ function Write-Trace {
28+ param (
29+ [string ]$Level ,
30+ [string ]$Message
31+ )
32+
33+ $timestamp = (Get-Date ).ToString(" yyyy-MM-dd HH:mm:ss.fff" )
34+ $entry = " $timestamp [$Level ] $Message "
35+ Add-Content - Path (Get-LogFilePath ) - Value $entry
36+ }
37+
38+ # =========================
39+ # Log retention cleanup
40+ # =========================
41+ $cutoffDate = (Get-Date ).Date.AddDays(- $LogRetentionDays )
42+
43+ Get-ChildItem - Path $LogDirectory - Filter " ReplayParkedSubscriptions-*.log" - File |
44+ Where-Object {
45+ if ($_.Name -match ' ReplayParkedSubscriptions-(\d{4}-\d{2}-\d{2})\.log' ) {
46+ [DateTime ]::ParseExact($matches [1 ], ' yyyy-MM-dd' , $null ) -lt $cutoffDate
47+ }
48+ else {
49+ $false
50+ }
51+ } |
52+ ForEach-Object {
53+ try {
54+ Remove-Item $_.FullName - Force
55+ }
56+ catch {
57+ # Avoid failing the run due to cleanup issues
58+ }
59+ }
60+
61+ Write-Trace " INFO" " Script started. BaseUrl=$BaseUrl "
62+
63+ # =========================
64+ # Auth header
65+ # =========================
66+ $AuthHeader = @ {
67+ Authorization = " Basic " +
68+ [Convert ]::ToBase64String(
69+ [Text.Encoding ]::ASCII.GetBytes(" $Username `:$Password " )
70+ )
71+ }
72+
73+ # =========================
74+ # Query subscriptions
75+ # =========================
76+ try {
77+ Write-Trace " INFO" " Querying persistent subscriptions"
78+ $subscriptions = Invoke-RestMethod `
79+ - Method GET `
80+ - Uri " $BaseUrl /subscriptions" `
81+ - Headers $AuthHeader
82+ }
83+ catch {
84+ Write-Trace " ERROR" " Failed to query subscriptions: $ ( $_.Exception.Message ) "
85+ exit 1
86+ }
87+
88+ # =========================
89+ # Process subscriptions
90+ # =========================
91+ foreach ($sub in $subscriptions ) {
92+
93+ $stream = $sub.eventStreamId
94+ $group = $sub.groupName
95+
96+ # Write-Trace "INFO" "Processing subscription [$stream][$group]"
97+
98+ $streamEncoded = if ($stream -eq ' $all' ) {
99+ ' %24all'
100+ }
101+ else {
102+ [System.Web.HttpUtility ]::UrlEncode($stream )
103+ }
104+
105+ $infoUrl = " $BaseUrl /subscriptions/$streamEncoded /$group /info"
106+
107+ try {
108+ $info = Invoke-RestMethod `
109+ - Method GET `
110+ - Uri $infoUrl `
111+ - Headers $AuthHeader
112+ }
113+ catch {
114+ Write-Trace " WARN" " Failed to get info for [$stream ][$group ]: $ ( $_.Exception.Message ) "
115+ continue
116+ }
117+
118+ $parkedCount = $info.parkedMessageCount
119+ # Write-Trace "INFO" "[$stream][$group] parkedMessageCount=$parkedCount"
120+
121+ if ($parkedCount -gt 0 ) {
122+ $replayUrl = " $BaseUrl /subscriptions/$streamEncoded /$group /replayParked?from=0"
123+
124+ Write-Trace " INFO" " Replaying [$parkedCount ] parked messages for [$stream ][$group ]"
125+
126+ try {
127+ Invoke-RestMethod `
128+ - Method POST `
129+ - Uri $replayUrl `
130+ - Headers $AuthHeader
131+
132+ Write-Trace " INFO" " Replay triggered successfully for [$stream ][$group ]"
133+ }
134+ catch {
135+ Write-Trace " ERROR" " Replay failed for [$stream ][$group ]: $ ( $_.Exception.Message ) "
136+ }
137+ }
138+ # else {
139+ # Write-Trace "INFO" "No parked messages for [$stream][$group]"
140+ # }
141+ }
142+
143+ Write-Trace " INFO" " Script completed"
0 commit comments