Skip to content

Commit

Permalink
Merge a1662a0 into 5f08318
Browse files Browse the repository at this point in the history
  • Loading branch information
Badgerati committed Apr 23, 2020
2 parents 5f08318 + a1662a0 commit 3c05c52
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 42 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -5,6 +5,7 @@
pode_modules/
ps_modules/
docs/[Ff]unctions/
examples/state.json


# Code Runner
Expand Down
28 changes: 16 additions & 12 deletions docs/Tutorials/SharedState.md
@@ -1,24 +1,24 @@
# Shared State

Most things in Pode all run in isolated runspaces, which means you can't create a variable in a timer and then access that variable in a route. To overcome this limitation you can use the State functions, which allows you to set/get variables on a state shared between all runspaces. This means you can create a variable in a timer and set it against the shared state; then you can retrieve the variable from the state in a route.
Most things in Pode run in isolated runspaces: routes, middleware, schedules - to name a few. This means you can't create a variable in a timer, or in the base server scope, and then access that variable in a route. To overcome this limitation you can use the Shared State feature within Pode, which allows you to set/get variables on a state shared between all runspaces. This lets you can create a variable in a timer and store it within the shared state; then you can retrieve the variable from the state in a route.

You also have the option of saving the current state to a file, and then restoring the state back on server start. This way you won't lose state between server restarts.

To do this, you use the State functions in combination with the [`Lock-PodeObject`](../../Functions/Utilities/Lock-PodeObject) function to ensure thread safety.
You can also use the State in combination with the [`Lock-PodeObject`](../../Functions/Utilities/Lock-PodeObject) function to ensure thread safety - if needed.

!!! tip
It's wise to use the State functions in conjunction with the [`Lock-PodeObject`](../../Functions/Utilities/Lock-PodeObject) function, to ensure thread safety between runspaces. The event argument supplied to the Routes, Handlers, Timers, Schedules, Middleware, Endware and Loggers each contain a `.Lockable` resource that can be supplied to the [`Lock-PodeObject`](../../Functions/Utilities/Lock-PodeObject) function.
It's wise to use the State in conjunction with the [`Lock-PodeObject`](../../Functions/Utilities/Lock-PodeObject) function, to ensure thread safety between runspaces. The event argument supplied to Routes, Handlers, Timers, Schedules, Middleware, Endware and Loggers each contain a `.Lockable` resource that can be supplied to the [`Lock-PodeObject`](../../Functions/Utilities/Lock-PodeObject) function.

!!! warning
If you omit the use of [`Lock-PodeObject`](../../Functions/Utilities/Lock-PodeObject), you will run into errors due to multi-threading. Only omit if you are *absolutely confident* you do not need locking. (ie: you set in state once and then only ever retrieve, never updating the variable).
If you omit the use of [`Lock-PodeObject`](../../Functions/Utilities/Lock-PodeObject), you will run into errors due to multi-threading. Only omit if you are *absolutely confident* you do not need locking. (ie: you set in state once and then only ever retrieve, never updating the variable).

## Usage

### Set

The [`Set-PodeState`](../../Functions/State/Set-PodeState) function will create/update a variable on the shared state. You need to supply a name and a value to set on the state.
The [`Set-PodeState`](../../Functions/State/Set-PodeState) function will create/update a variable in the state. You need to supply a name and a value to set on the state, there's also an optional scope that can be supplied - which lets you save specific state objects with a certain scope.

An example of setting a shared hashtable variable is as follows:
An example of setting a hashtable variable in the state is as follows:

```powershell
Start-PodeServer {
Expand All @@ -34,9 +34,9 @@ Start-PodeServer {

### Get

The [`Get-PodeState`](../../Functions/State/Get-PodeState) function will return the value currently stored on the shared state for a variable. If the variable doesn't exist then `$null` is returned.
The [`Get-PodeState`](../../Functions/State/Get-PodeState) function will return the value currently stored in the state for a variable. If the variable doesn't exist then `$null` is returned.

An example of retrieving the value from the shared state is as follows:
An example of retrieving a value from the state is as follows:

```powershell
Start-PodeServer {
Expand All @@ -55,9 +55,9 @@ Start-PodeServer {

### Remove

The [`Remove-PodeState`](../../Functions/State/Remove-PodeState) function will remove a variable from the shared state. It will also return the value stored in the state before removing the variable.
The [`Remove-PodeState`](../../Functions/State/Remove-PodeState) function will remove a variable from the state. It will also return the value stored in the state before removing the variable.

An example of removing a variable from the shared state is as follows:
An example of removing a variable from the state is as follows:

```powershell
Start-PodeServer {
Expand All @@ -73,7 +73,7 @@ Start-PodeServer {

### Save

The [`Save-PodeState`](../../Functions/State/Save-PodeState) function will save the current state, as JSON, to the specified file. The file path can either be relative, or a literal path. When saving the state, it's recommended to wrap the function within a [`Lock-PodeObject`](../../Functions/Utilities/Lock-PodeObject).
The [`Save-PodeState`](../../Functions/State/Save-PodeState) function will save the current state, as JSON, to the specified file. The file path can either be relative, or literal. When saving the state, it's recommended to wrap the function within [`Lock-PodeObject`](../../Functions/Utilities/Lock-PodeObject).

An example of saving the current state every hour is as follows:

Expand All @@ -87,9 +87,13 @@ Start-PodeServer {
}
```

When saving the state, you can also use the `-Exclude` or `-Include` parameters to exclude/include certain state objects from being saved. Saving also has a `-Scope` parameter, which allows you so save only state objects created with the specified scope(s).

You can use all the above 3 parameter in conjunction, with `-Exclude` having the highest precedence and `-Scope` having the lowest.

### Restore

The [`Restore-PodeState`](../../Functions/State/Restore-PodeState) function will restore the current state from the specified file. The file path can either be relative, or a literal path. if you're restoring the state immediately on server start, you don't need to use [`Lock-PodeObject`](../../Functions/Utilities/Lock-PodeObject).
The [`Restore-PodeState`](../../Functions/State/Restore-PodeState) function will restore the current state from the specified file. The file path can either be relative, or a literal path. if you're restoring the state immediately on server start, you don't need to use [`Lock-PodeObject`](../../Functions/Utilities/Lock-PodeObject).

An example of restore the current state on server start is as follows:

Expand Down
18 changes: 12 additions & 6 deletions examples/shared-state.ps1
Expand Up @@ -7,15 +7,21 @@ Import-Module "$($path)/src/Pode.psm1" -Force -ErrorAction Stop
# create a basic server
Start-PodeServer {

Add-PodeEndpoint -Address * -Port 8085 -Protocol Http
Add-PodeEndpoint -Address * -Port 8090 -Protocol Http
New-PodeLoggingMethod -Terminal | Enable-PodeRequestLogging
New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging

# re-initialise the state
Restore-PodeState -Path './state.json'

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

if ($null -eq ($hash = (Get-PodeState -Name 'hash2'))) {
$hash = Set-PodeState -Name 'hash2' -Value @{} -Scope Scope0, Scope2
$hash['values'] = @()
}

Expand All @@ -25,9 +31,9 @@ Start-PodeServer {
$hash = $null

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

Expand All @@ -36,7 +42,7 @@ Start-PodeServer {
param($session)

Lock-PodeObject -Object $session.Lockable {
$hash = (Get-PodeState 'hash')
$hash = (Get-PodeState 'hash1')
Write-PodeJsonResponse -Value $hash
}
}
Expand Down

0 comments on commit 3c05c52

Please sign in to comment.