Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
2e55aac
first drop
mdaneri Feb 2, 2025
afaabe9
working version
mdaneri Feb 2, 2025
0e0694c
final
mdaneri Feb 3, 2025
1ad2334
fixes
mdaneri Feb 3, 2025
37226cf
fixes and doc update
mdaneri Feb 3, 2025
aab9fa5
Update SharedState.md
mdaneri Feb 3, 2025
556ef81
update
mdaneri Feb 4, 2025
c634e0a
Delete System.Collections.Hashtable
mdaneri Feb 4, 2025
81802c1
fix compatibility with older versions
mdaneri Feb 4, 2025
fc41e3c
Add translations
mdaneri Feb 4, 2025
8594cc5
remove Get-PodeApplicationName
mdaneri Feb 4, 2025
8f50237
improvement
mdaneri Feb 4, 2025
aae3d5d
fix tests
mdaneri Feb 4, 2025
f2d70fa
Update State.Tests.ps1
mdaneri Feb 4, 2025
18dcdd6
Update Convert.ps1
mdaneri Feb 4, 2025
a893127
Get-PodeUtcNow
mdaneri Feb 4, 2025
b7b085c
Merge branch 'develop' into threadsafe-state
mdaneri Feb 5, 2025
be8f407
Merge remote-tracking branch 'upstream/develop' into threadsafe-state
mdaneri Feb 9, 2025
a1beca3
Merge remote-tracking branch 'upstream/develop' into threadsafe-state
mdaneri Feb 12, 2025
f073f50
Merge branch 'develop' into threadsafe-state
mdaneri Feb 16, 2025
a3de2b3
Merge branch 'develop' into threadsafe-state
mdaneri Feb 22, 2025
e40e0d9
Merge remote-tracking branch 'upstream/develop' into threadsafe-state
mdaneri Feb 22, 2025
77a56a1
Merge branch 'develop' into threadsafe-state
mdaneri Feb 23, 2025
a662515
fix helper
mdaneri Mar 1, 2025
d15f399
simplify merge
mdaneri Mar 2, 2025
11ced8e
fix tests
mdaneri Mar 2, 2025
7cbeabc
Fix PSObject to hashtable conversion
mdaneri Mar 2, 2025
72e9350
sorted languages
mdaneri Mar 7, 2025
f7a1c91
Merge remote-tracking branch 'upstream/develop' into threadsafe-state
mdaneri Mar 18, 2025
12892d3
.
mdaneri Mar 28, 2025
9110725
Added new Convert State functions
mdaneri Mar 29, 2025
1d54c92
Update SharedState.md
mdaneri Mar 29, 2025
ab970f5
Merge remote-tracking branch 'upstream/develop' into threadsafe-state
mdaneri Mar 29, 2025
0806181
Added -Force parameter
mdaneri Mar 30, 2025
1f65e13
Fix merge
mdaneri Apr 3, 2025
eb042ac
Merge remote-tracking branch 'upstream/develop' into threadsafe-state
mdaneri Apr 12, 2025
94383ce
Merge branch 'develop' into threadsafe-state
mdaneri Apr 12, 2025
d7e2545
Merge remote-tracking branch 'upstream/develop' into threadsafe-state
mdaneri Apr 19, 2025
dcbf307
Merge remote-tracking branch 'upstream/develop' into threadsafe-state
mdaneri Apr 21, 2025
51d28e5
Merge branch 'develop' into threadsafe-state
mdaneri Apr 25, 2025
36a242f
Merge branch 'develop' into threadsafe-state
mdaneri Apr 26, 2025
5c801ec
Merge branch 'develop' into threadsafe-state
mdaneri Apr 27, 2025
61a5764
Fix merge with prerelease
mdaneri May 18, 2025
a13d64c
Update Utilities.ps1
mdaneri May 18, 2025
94ce3fa
Update Helpers.ps1
mdaneri May 19, 2025
6ca90e0
Revert "Update Helpers.ps1"
mdaneri May 19, 2025
f56f8a2
Update Helpers.ps1
mdaneri May 19, 2025
617c8ca
Update pode.build.ps1
mdaneri May 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ docs/[Ff]unctions/
examples/state.json
examples/issue-*
examples/issues/
examples/State/
pkg/
deliverable/
.vs/
Expand Down Expand Up @@ -271,3 +272,4 @@ docs/Getting-Started/Samples.md

# Dump Folder
Dump

255 changes: 181 additions & 74 deletions docs/Tutorials/SharedState.md

Large diffs are not rendered by default.

32 changes: 26 additions & 6 deletions examples/Shared-State.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,34 @@ Start-PodeServer {
Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http
New-PodeLoggingMethod -Terminal | Enable-PodeRequestLogging
New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging
$Path = Join-Path (Get-PodeServerPath) "State"

if (!(Test-Path -Path $Path -PathType Container)) {
New-Item -Path $Path -ItemType Directory

}
$stateScope1Path = Join-Path -Path $Path -ChildPath 'LegacyStateScope1.json'
#if no previous state exist create a new one old Pode style
if (!( Test-Path $stateScope1Path)) {
@{
'hash1' = @{
'Scope' = @('Scope0', 'Scope1')
'Value' = @{
'values' = @(4, 4, 8, 0, 5, 5, 1, 9, 1, 1, 2, 4, 9, 2, 5)
}
}
} | ConvertTo-Json -Depth 10 | Out-File $stateScope1Path
}
# re-initialise the state
Restore-PodeState -Path './state.json'
Restore-PodeState -Path $stateScope1Path

# initialise if there was no file
if ($null -eq ($hash = (Get-PodeState -Name 'hash1'))) {
if (!(Test-PodeState -Name 'hash1')) {
$hash = Set-PodeState -Name 'hash1' -Value @{} -Scope Scope0, Scope1
$hash['values'] = @()
}

if ($null -eq ($hash = (Get-PodeState -Name 'hash2'))) {
if (!(Test-PodeState -Name 'hash2')) {
$hash = Set-PodeState -Name 'hash2' -Value @{} -Scope Scope0, Scope2
$hash['values'] = @()
}
Expand All @@ -63,14 +80,17 @@ Start-PodeServer {
$state:hash3 = @{ values = @() }
}

Save-PodeState -Path $stateScope1Path -Scope Scope1

# create timer to update a hashtable and make it globally accessible
Add-PodeTimer -Name 'forever' -Interval 2 -ScriptBlock {
Add-PodeTimer -Name 'forever' -Interval 2 -ArgumentList $stateScope1Path -ScriptBlock {
param([string]$stateScope1Path)
$hash = $null

Lock-PodeObject -ScriptBlock {
$hash = (Get-PodeState -Name 'hash1')
$hash.values += (Get-Random -Minimum 0 -Maximum 10)
Save-PodeState -Path './state.json' -Scope Scope1 #-Exclude 'hash1'
Save-PodeState -Path $stateScope1Path -Scope Scope1 #-Exclude 'hash1'
}

Lock-PodeObject -ScriptBlock {
Expand All @@ -95,7 +115,7 @@ Start-PodeServer {
# route to remove the hashtable from global state
Add-PodeRoute -Method Delete -Path '/array' -ScriptBlock {
Lock-PodeObject -ScriptBlock {
$hash = (Set-PodeState -Name 'hash1' -Value @{})
$hash = (Set-PodeState -Name 'hash1' -Value @{} -Scope Scope0, Scope1)
$hash.values = @()
}
}
Expand Down
138 changes: 138 additions & 0 deletions examples/Shared-ThreadSafeState.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<#
.SYNOPSIS
A sample PowerShell script to set up a Pode server with thread-safe state management and logging.

.DESCRIPTION
This script sets up a Pode server that listens on port 8081, logs requests and errors to the terminal, and manages state using thread-safe collections such as `ConcurrentDictionary` and `ConcurrentBag`. The server initializes state from a JSON file, updates state periodically using timers, and provides routes to interact with the state.

.EXAMPLE
To run the sample: ./Shared-ThreadSafeState.ps1

Invoke-RestMethod -Uri http://localhost:8081/array -Method Get
Invoke-RestMethod -Uri http://localhost:8081/array3 -Method Get
Invoke-RestMethod -Uri http://localhost:8081/array -Method Delete

.LINK
https://github.com/Badgerati/Pode/blob/develop/examples/Shared-ThreadSafeState.ps1

.NOTES
Author: Pode Team
License: MIT License
This script uses `ConcurrentDictionary` and `ConcurrentBag` to ensure thread-safe state handling in a multi-threaded Pode environment.
#>

try {
# Determine the script path and Pode module path
$ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path)
$podePath = Split-Path -Parent -Path $ScriptPath

# Import the Pode module from the source path if it exists, otherwise from installed modules
if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) {
Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop
}
else {
Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop
}
}
catch { throw }

# or just:
# Import-Module Pode

# create a basic server
Start-PodeServer {

Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http
New-PodeLoggingMethod -Terminal | Enable-PodeRequestLogging
New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging
$Path = Get-PodeRelativePath -Path './State' -JoinRoot -Resolve

if (!(Test-Path -Path $Path -PathType Container)) {
New-Item -Path $Path -ItemType Directory

}
$stateScope1Path = Join-Path -Path $Path -ChildPath 'ThreadSafeStateScope1.json'
$stateScope2Path = Join-Path -Path $Path -ChildPath 'ThreadSafeStateScope2.json'
$stateScope0Path = Join-Path -Path $Path -ChildPath 'ThreadSafeStateScope0.json'
$stateNoScopePath = Join-Path -Path $Path -ChildPath 'ThreadSafeStateNoScope.json'
# re-initialise the state
Restore-PodeState -Path $stateScope1Path
Restore-PodeState -Path $stateScope2Path -Merge
Save-PodeState -Path $stateNoScopePath
# initialise if there was no file
if (!(Test-PodeState -Name 'hash1')) {
$hash = (Set-PodeState -Name 'hash1' -NewCollectionType ConcurrentDictionary -Scope Scope0, Scope1 )
$hash.bag = [System.Collections.Concurrent.ConcurrentBag[object]]::new()
$hash.array = @()
$hash.psCustomSum = [PSCustomObject]@{
bag = 0
array = 0
}
$hash.string = 'Never deleted'
$hash.deleted = 0
# Assign a custom PsTypeName
$hash.psCustomSum.PSTypeNames.Insert(0, 'Pode.StateSum')
}

if (!(Test-PodeState -Name 'hash2')) {
$hash = Set-PodeState -Name 'hash2' -NewCollectionType Hashtable -Scope Scope0, Scope2
$hash['values'] = @()
}

if ($null -eq $state:hash3) {
$state:hash3 = @{ values = @() }
}

# create timer to update a hashtable and make it globally accessible
Add-PodeTimer -Name 'forever' -Interval 2 -ArgumentList $stateScope1Path, $stateScope2Path, $stateScope0Path, $stateNoScopePath -ScriptBlock {
param([string]$stateScope1Path, [string]$stateScope2Path, [string]$stateScope0Path, [string]$stateNoScopePath)
$hash = $null

$hash = (Get-PodeState -Name 'hash1')
$hash.bag.add((Get-Random -Minimum 0 -Maximum 10))
$hash.array += (Get-Random -Minimum 0 -Maximum 10)

$hash.psCustomSum.bag = $hash.bag.ToArray() | Measure-Object -Sum | Select-Object -ExpandProperty Sum
$hash.psCustomSum.array = $hash.array | Measure-Object -Sum | Select-Object -ExpandProperty Sum


$state:hash3.values += (Get-Random -Minimum 0 -Maximum 10)

$hash2 = (Get-PodeState -Name 'hash2')
$hash2.values += (Get-Random -Minimum 100 -Maximum 200)
Save-PodeState -Path $stateScope1Path -Scope Scope1 #-Exclude 'hash2'
Save-PodeState -Path $stateScope2Path -Scope Scope2
Save-PodeState -Path $stateScope0Path -Scope Scope0
Save-PodeState -Path $stateNoScopePath
}

# route to retrieve and return the value of the hashtable from global state
Add-PodeRoute -Method Get -Path '/array' -ScriptBlock {
$hash = (Get-PodeState 'hash1')
Write-PodeJsonResponse -Value $hash
}

Add-PodeRoute -Method Get -Path '/array3' -ScriptBlock {
Write-PodeJsonResponse -Value $state:hash3
}

# route to remove the hashtable from global state
Add-PodeRoute -Method Delete -Path '/array' -ScriptBlock {
$value = (Get-PodeState -Name 'hash1' )
$hash = (Set-PodeState -Name 'hash1' -NewCollectionType ConcurrentDictionary -Scope Scope0, Scope1 )
$hash.bag = [System.Collections.Concurrent.ConcurrentBag[object]]::new()
$hash.bag.add((Get-Random -Minimum 0 -Maximum 10))
$hash.array = @((Get-Random -Minimum 0 -Maximum 10))

$hash.psCustomSum = [PSCustomObject]@{
bag = $hash.bag.ToArray() | Measure-Object -Sum | Select-Object -ExpandProperty Sum
array = $hash.array | Measure-Object -Sum | Select-Object -ExpandProperty Sum
}
# Assign a custom PsTypeName
$hash.psCustomSum.PSTypeNames.Insert(0, 'Pode.StateSum')
$hash.deleted = $value.number + 1
$hash.string = "Deleted $($hash.number) times"

}

}
Empty file added examples/ThreadSafeState.json
Empty file.
1 change: 1 addition & 0 deletions examples/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"Type":"ConcurrentDictionary","Items":[{"Key":"Name","Value":{"Type":"ConcurrentDictionary","Items":[{"Key":"Value","Value":{"Type":"Hashtable","Items":[{"Key":"Name","Value":"Morty"}]}},{"Key":"Scope","Value":null}]}}]}
2 changes: 1 addition & 1 deletion pode.build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -1817,4 +1817,4 @@ task ReleaseNotes {
$categories[$category] | Sort-Object | ForEach-Object { Write-Host $_ }
Write-Host ''
}
}
}
Loading
Loading