Skip to content

Session Service Basics#

Tip

Explore the gRPC API using gRPC UI.

This provides an intuitive web interface to issue API calls and see the responses.

Opening a Channel#

The network connection to a server is called a channel in most gRPC bindings.
This should be reused across service calls where possible, for efficiency.

The session store service is provided by the Toolkit Session Service (default port 2652) and RTA Server (default port 8082).

using var sessionChannel = GrpcChannel.ForAddress("http://localhost:2652");
var sessionClient = new SessionStore.SessionStoreClient(sessionChannel);

Creating/Updating a Session#

In this example, CreateIfNotExists defines the initial properties to set if the session does not already exist, along with Updates to be applied in the same transaction.

If the session does exist, only the Updates are applied.

await sessionClient.CreateOrUpdateSessionAsync(new CreateOrUpdateSessionRequest
{
    Identity = "001",
    CreateIfNotExists = new()
    {
        Identifier = "Demo Session",
        Timestamp = "2021-03-14T12:15:30Z",
        State = (int)SessionState.Closed
    }
});
{
    "identity": "001",
    "state": "closed",
    "timestamp": "2021-03-14T12:15:30Z",
    "identifier": "Demo session"
}

Each SessionUpdate can only do one operation:

Incorrect

In this example, only SetQuality is executed:

await sessionClient.CreateOrUpdateSessionAsync(new CreateOrUpdateSessionRequest
{
    Identity = "example",
    Updates =
    {
        new SessionUpdate
        {
            SetType = "type66",
            SetQuality = 0.25
        }
    }
});
Correct

In this example, SetType and SetQuality are executed in a single transaction:

await sessionClient.CreateOrUpdateSessionAsync(new CreateOrUpdateSessionRequest
{
    Identity = "example",
    Updates =
    {
        new SessionUpdate
        {
            SetType = "type66"
        },
        new SessionUpdate
        {
            SetQuality = 0.25
        }
    }
});

Updates to collections offer a consistent pattern of operations:

  • Set... — overwrites the collection
  • Update... — adds and updates items
  • Delete... — deletes the specified items

For example, when defining relationships, these two samples are equivalent:

Starting with "ref:aaa", "ref:bbb", "ref:ccc"
await sessionClient.CreateOrUpdateSessionAsync(new CreateOrUpdateSessionRequest
{
    Identity = "example",
    Updates =
    {
        new SessionUpdate
        {
            SetRefAnchors = new()
            {
                RefUris =
                {
                    "ref:aaa",
                    "ref:bbb",
                    "ref:ccc"
                }
            }
        }
    }
});

Merge update using Update and Delete:

await sessionClient.CreateOrUpdateSessionAsync(new CreateOrUpdateSessionRequest
{
    Identity = "example",
    Updates =
    {
        new SessionUpdate
        {
            UpdateRefAnchors = new()
            {
                RefUris =
                {
                    "ref:ccc",
                    "ref:ddd"
                }
            }
        },
        new SessionUpdate
        {
            DeleteRefAnchors = new()
            {
                RefUris =
                {
                    "ref:aaa"
                }
            }
        }
    }
});

Result:

  • "ref:bbb"
  • "ref:ccc"
  • "ref:ddd"

Note

Notice that the overlap with "ref:ccc" is allowed. This is similar to JSON patching.

Starting with "ref:aaa", "ref:bbb", "ref:ccc"
await sessionClient.CreateOrUpdateSessionAsync(new CreateOrUpdateSessionRequest
{
    Identity = "example",
    Updates =
    {
        new SessionUpdate
        {
            SetRefAnchors = new()
            {
                RefUris =
                {
                    "ref:aaa",
                    "ref:bbb",
                    "ref:ccc"
                }
            }
        }
    }
});

Overwriting with Set:

await sessionClient.CreateOrUpdateSessionAsync(new CreateOrUpdateSessionRequest
{
    Identity = "example",
    Updates =
    {
        new SessionUpdate
        {
            SetRefAnchors = new()
            {
                RefUris =
                {
                    "ref:bbb",
                    "ref:ccc",
                    "ref:ddd"
                }
            }
        }
    }
});

Result:

  • "ref:bbb"
  • "ref:ccc"
  • "ref:ddd"

Note

Notice that "ref:aaa" is removed from the list.

Fetching and Listing Sessions#

The Session Service API provides the same query capabilities as the REST API, but with an extended data model covering Relationships, Folders and Data Bindings.

These elements are opt-in through the SessionElements mask:

var session = await sessionClient.GetSessionAsync(new GetSessionRequest
{
    Identity = "example",
    Elements = new()
    {
        Json = true,
        Refs = true,
        Folders = true,
        DataBindings = true
    }
});

Tip

The MAT.OCS.RTA.Toolkit.API.GrpcClients NuGet package provides a convenience method to retrieve and parse the JSON Session Model:

var sessionModel = await sessionClient.GetSessionJsonAsync("example");

Listing sessions works the same way, using the same query dialect as the REST API:

var list = await sessionClient.ListSessionsAsync(new ListSessionsRequest
{
    Query = "{\"identifier\": \"Example\"}",
    SessionElements = new()
    {
        Json = true,
        DataBindings = true
    }
});

Sequenced Updates#

The CreateOrUpdateSessionRequest has an optional sequence field, which can help avoid re-applying stale session updates when working with a checkpoint-based system like Apache Kafka.

If populated, the service will apply the update only if the specified sequence number is greater than previous sequence numbers. As the sequence monotonically increases — for example, using a Kafka message offset — it is safe to replay a sequence of updates without causing the session metadata to roll back.

await sessionClient.CreateOrUpdateSessionAsync(new CreateOrUpdateSessionRequest
{
    Identity = "example",
    Sequence = 100,
    Updates =
    {
        new SessionUpdate
        {
            SetType = "aaa"
        }
    }
});

await sessionClient.CreateOrUpdateSessionAsync(new CreateOrUpdateSessionRequest
{
    Identity = "example",
    Sequence = 120,
    Updates =
    {
        new SessionUpdate
        {
            SetType = "bbb"
        }
    }
});

Deleting Sessions#

Multiple sessions can be deleted in one operation, and deletion completes without error even if a session does not exist:

await sessionClient.DeleteSessionsAsync(new DeleteSessionsRequest
{
    Identities =
    {
        "example",
        "xxx-does-not-exist-xxx"
    }
});