Global Dictionary¶
The Runner global dictionary is the shared mutable state that lives alongside the built execution. Use it when values must be available at runtime across hooks, sessions, assertions, and other execution components.
This is the recommended replacement for the old Framework-specific Variables runtime helper. YAML variables still remain a valid configuration section for placeholders, but if you want those values inside runtime code, project that section into the global dictionary.
Runner now does that projection automatically by default. When a built execution has a root variables section, Runner copies it into the shared global dictionary under Variables.
What It Is For¶
Use the global dictionary when you need to:
- share values between hooks during one Runner invocation
- keep runtime state separate from the immutable YAML shape
- preload configuration sections such as
variablesinto code-visible state - seed values before execution starts
- let selected probes persist recovery state and shared defaults between related probe steps in the same execution and session
Probe Global Dictionary Fallback¶
Selected probes in QaaS.Common.Probes can now opt into global-dictionary-backed configuration fallback through:
When UseGlobalDict is true, the probe merges configuration in this order:
- probe-global-dictionary defaults and recovery payloads
- local YAML or code configuration
- normal bind and validation
This merge is based on raw key presence, not typed defaults. That means an omitted key can come from the global dictionary, but an explicit local value such as false, 0, "", or an empty collection still wins and keeps current behavior.
When UseGlobalDict is false, the current behavior remains unchanged: the probe reads only its local configuration and does not use probe-global-dictionary state.
Probe Storage Paths¶
Probe-global-dictionary writes are scoped uniquely per execution, session, and probe:
<execution-scope> follows the Runner artifact convention:
ExecutionId::CaseNamewhen those values existcontext::<hash>only as a fallback for direct in-memory usage outside the normal Runner execution flow
Family aliases then point to those canonical entries:
The alias is what later probes read. The canonical scoped path is what keeps every probe execution isolated, even when several probes in the same session use the same family alias.
Recovery Example: Delete Then Recreate RabbitMQ Exchanges¶
One intended use case is recovery testing:
DeleteRabbitMqExchangesruns withUseGlobalDict: true- it writes the resolved broker defaults under the session-scoped
RabbitMq/AmqpDefaultsalias - it writes the deleted exchange list under
RabbitMq/Recovery/Exchanges CreateRabbitMqExchangeslater runs in the same execution and session withUseGlobalDict: true- if local
Host,Port,Username,Password,VirtualHost, orExchangeskeys are missing, the create probe restores them from those aliases
Example:
Sessions:
- Name: RecoverySession
Probes:
- Name: DeleteExchanges
Probe: DeleteRabbitMqExchanges
ProbeConfiguration:
UseGlobalDict: true
Host: rabbitmq.local
Username: guest
Password: guest
Port: 5672
VirtualHost: /
ExchangeNames:
- orders.exchange
- Name: RecreateExchanges
Probe: CreateRabbitMqExchanges
ProbeConfiguration:
UseGlobalDict: true
The second probe can omit the exchange list because the first probe already captured it in the scoped probe global dictionary for that execution and session.
Which Probes Use It¶
The first pass enables probe-global-dictionary fallback for:
- RabbitMQ lifecycle and definitions probes
- OpenShift deployment and stateful-set mutation probes, plus config-map editing
- Redis maintenance and command probes
- Elasticsearch cleanup probes
- MongoDB cleanup probes
- S3 bucket maintenance probes
- SQL truncate probes
Two OpenShift probes are intentionally excluded in this first pass because they do not have a meaningful reusable recovery payload:
OsRestartPodsOsExecuteCommandsInContainers
For the exact Framework API surface, see Context global dictionary and ExecutionBuilder configuration helpers.
Placeholder Values vs Runtime State¶
These two concepts are related but not the same:
- the YAML
variablessection is part of configuration and is mainly used by placeholder resolution such as${variables:rabbitmq:host} - the global dictionary is mutable runtime state stored on the execution context
By default, Runner also loads that configuration section into runtime state under Variables, so runtime code can read the same values without relying on a separate Variables feature.
Runner Default: Auto-Load variables Into Variables¶
If the loaded configuration contains:
Runner builds each execution with:
var host = context.GetValueFromGlobalDictionary(["Variables", "rabbitmq", "host"]);
var port = context.GetValueFromGlobalDictionary(["Variables", "rabbitmq", "port"]);
The default is controlled by Runner.LoadVariablesIntoGlobalDict, which starts as true.
Custom runner types can also override that property:
public sealed class MyRunner : Runner
{
public override bool LoadVariablesIntoGlobalDict { get; set; } = false;
}
Turn it off only if you want to keep variables available for placeholder resolution but do not want those values copied into mutable runtime state.
Load the variables Section Into the Global Dictionary Manually¶
Inside a hook or any place where you already have access to the current context:
using QaaS.Framework.SDK.Extensions;
context.LoadConfigurationSectionIntoGlobalDictionary("variables");
That projects:
into a runtime path that can be read as:
var host = context.GetValueFromGlobalDictionary(["variables", "rabbitmq", "host"]);
var port = context.GetValueFromGlobalDictionary(["variables", "rabbitmq", "port"]);
Use the manual form when:
- you disabled
Runner.LoadVariablesIntoGlobalDict - you want to load the section later in the runtime flow instead of during build
- you want the runtime path to stay lowercase
variablesfor compatibility with older hook code
Load a Section Into a Different Runtime Path¶
You are not limited to reusing the configuration path as-is. You can project a section into any destination path:
using QaaS.Framework.SDK.Extensions;
context.LoadConfigurationSectionIntoGlobalDictionary(
"variables:rabbitmq",
["runtime", "rabbitmq"]);
Then read it from:
Use this when:
- several configuration sections should be normalized under one runtime root
- a hook wants a shorter or more domain-specific path
- you want to keep the original configuration path separate from the runtime path
Seed Values Before Execution Starts¶
If you already know runtime values before the execution is built, preload them through the execution builder:
using QaaS.Runner;
var runner = Bootstrap.New(args);
var executionBuilder = runner.ExecutionBuilders.AsSingle();
executionBuilder.WithGlobalDict(new Dictionary<string, object?>
{
["environment"] = new Dictionary<string, object?>
{
["name"] = "local"
}
});
Runner pushes one shared global dictionary into the execution builders that belong to the same runner invocation, so this is the right place for per-run state that should already exist before hooks start.
Add or Update Runtime Values During Execution¶
You can create or overwrite paths at any time:
This is useful for:
- values discovered during setup
- IDs returned from publishers, consumers, or probes
- data that later assertions or cleanup hooks need
Read Runtime Values Safely¶
If the path does not exist, QaaS throws a KeyNotFoundException. That is usually preferable to silently continuing with the wrong runtime state.
Recommended Pattern for Variables Files¶
If your project already uses overwrite files such as Variables/local.yaml and Variables/k8s.yaml, keep doing that for placeholder resolution. When runtime code also needs those values:
- load the YAML or overwrite files through the normal Runner bootstrap path
- rely on the default Runner auto-load into
["Variables", ...], or callcontext.LoadConfigurationSectionIntoGlobalDictionary("variables")yourself if you disabled that default - read the values from the global dictionary in later hooks
This keeps one source of truth for environment-specific values while removing the need for a dedicated Variables runtime object.
Example¶
using QaaS.Framework.SDK.Extensions;
using QaaS.Runner;
var runner = Bootstrap.New(["run", "test.qaas.yaml"]);
var executionBuilder = runner.ExecutionBuilders.AsSingle();
executionBuilder.WithGlobalDict(new Dictionary<string, object?>
{
["runtime"] = new Dictionary<string, object?>
{
["startedBy"] = Environment.UserName
}
});
var rabbitMqHost = context.GetValueFromGlobalDictionary(["Variables", "rabbitmq", "host"]);
This gives you both:
- immutable configuration values coming from YAML and overwrite files
- mutable runtime values stored in one shared global dictionary