Skip to content

Caching

Pode has an inbuilt in-memory caching feature, allowing you to cache values for a duration of time to speed up slower queries. You can also set up custom caching storage solutions - such as Redis, and others.

The default TTL for cached items is 3,600 seconds (1 hour), and this value can be customised either globally or per item. There is also a $cache: scoped variable available for use.

Caching Items

To add an item to the cache use Set-PodeCache, and then to retrieve the value from the cache use Get-PodeCache. If the item has expired when Get-PodeCache is called then $null will be returned.

For example, the following would retrieve the current CPU on Windows machines and cache it for 60 seconds:

Add-PodeRoute -Method Get -Path '/' -ScriptBlock {
    # check cache
    $cpu = Get-PodeCache -Key 'cpu'
    if ($null -ne $cpu) {
        Write-PodeJsonResponse -Value @{ CPU = $cpu }
        return
    }

    # get cpu, and cache for 60s
    $cpu = (Get-Counter '\Processor(_Total)\% Processor Time').CounterSamples.CookedValue
    $cpu | Set-PodeCache -Key 'cpu' -Ttl 60

    Write-PodeJsonResponse -Value @{ CPU = $cpu }
}

Alternatively, you could use the $cache: scoped variable instead. However, using this there is no way to pass the TTL when setting new cached items, so all items cached in this manner will use the default TTL (1 hour, unless changed). Changing the default TTL is discussed below.

Add-PodeRoute -Method Get -Path '/' -ScriptBlock {
    # check cache
    $cpu = $cache:cpu
    if ($null -ne $cpu) {
        Write-PodeJsonResponse -Value @{ CPU = $cpu }
        return
    }

    # get cpu, and cache for 1hr
    $cache:cpu = (Get-Counter '\Processor(_Total)\% Processor Time').CounterSamples.CookedValue
    Write-PodeJsonResponse -Value @{ CPU = $cache:cpu }
}

You can test if an item exists in the cache, and isn't expired, using Test-PodeCache - this is useful to call if the cached value for a key happens to genuinely be $null, so you can see if the key does exist.

If you need to invalidate a cached value you can use Remove-PodeCache, or if you need to invalidate the whole cache you can use Clear-PodeCache.

Default TTL

The default TTL for cached items, when the server starts, is 1 hour. This can be changed by using Set-PodeCacheDefaultTtl. The following updates the default TTL to 60 seconds:

Start-PodeServer {
    Set-PodeCacheDefaultTtl -Value 60
}

All new cached items will use this TTL by default unless the one is explicitly specified on Set-PodeCache using the -Ttl parameter.

Custom Storage

The inbuilt storage used by Pode is a simple in-memory synchronized hashtable, if you're running multiple instances of your Pode server then you'll have multiple caches as well - potentially with different values for the keys.

You can set up custom storage devices for your cached values using Add-PodeCacheStorage - you can also set up multiple different storages, and specify where certain items should be cached using the -Storage parameter on Get-PodeCache and Set-PodeCache.

When setting up a new cache storage, you are required to specific a series of scriptblocks for:

  • Setting a cached item (create/update). (-Set)
  • Getting a cached item's value. (-Get)
  • Testing if a cached item exists. (-Test)
  • Removing a cached item. (-Remove)
  • Clearing a cache of all items. (-Clear)

Note

Not all providers will support all options, such as clearing the whole cache. When this is the case simply pass an empty scriptblock to the parameter.

The -Test and -Remove scriptblocks will each be supplied the key for the cached item; the -Test scriptblock should return a boolean value. The -Set scriptblock will be supplied with the key, value, and TTL for the cached item. The -Get scriptblock will be supplied with the key of the item to retrieve, but also a boolean "metadata" flag - if this metadata flag is false, just return the item's value, but if it's true return a hashtable of the value and other metadata properties for expiry and ttl.

For example, say you want to use Redis to store your cached items, then you would have a similar setup to the one below.

$params = @{
    Set    = {
        param($key, $value, $ttl)
        $null = redis-cli -h localhost -p 6379 SET $key "$($value)" EX $ttl
    }
    Get    = {
        param($key, $metadata)
        $result = redis-cli -h localhost -p 6379 GET $key
        $result = [System.Management.Automation.Internal.StringDecorated]::new($result).ToString('PlainText')
        if ([string]::IsNullOrEmpty($result) -or ($result -ieq '(nil)')) {
            return $null
        }

        if ($metadata) {
            $ttl = redis-cli -h localhost -p 6379 TTL $key
            $ttl = [int]([System.Management.Automation.Internal.StringDecorated]::new($result).ToString('PlainText'))

            $result = @{
                Value = $result
                Ttl = $ttl
                Expiry = [datetime]::UtcNow.AddSeconds($ttl)
            }
        }

        return $result
    }
    Test   = {
        param($key)
        $result = redis-cli -h localhost -p 6379 EXISTS $key
        return ([System.Management.Automation.Internal.StringDecorated]::new($result).ToString('PlainText') -eq '1')
    }
    Remove = {
        param($key)
        $null = redis-cli -h localhost -p 6379 EXPIRE $key -1
    }
    Clear  = {}
}

Add-PodeCacheStorage -Name 'Redis' @params

Then to use the storage, pass the name to the -Storage parameter:

Add-PodeRoute -Method Get -Path '/' -ScriptBlock {
    # check cache
    $cpu = Get-PodeCache -Key 'cpu' -Storage 'Redis'
    if ($null -ne $cpu) {
        Write-PodeJsonResponse -Value @{ CPU = $cpu }
        return
    }

    # get cpu, and cache for 60s
    $cpu = (Get-Counter '\Processor(_Total)\% Processor Time').CounterSamples.CookedValue
    $cpu | Set-PodeCache -Key 'cpu' -Ttl 60 -Storage 'Redis'

    Write-PodeJsonResponse -Value @{ CPU = $cpu }
}

Default Storage

Similar to the TTL, you can change the default cache storage from Pode's in-memory one to a custom-added one. This default storage will be used for all cached items when -Storage is supplied, and when using $cache: as well.

Start-PodeServer {
    Set-PodeCacheDefaultStorage -Name 'Redis'
}