Welcome to the Janison Insights help portal

Test delivery messaging

Janison uses Microsoft Azure Event Hub & Microsoft Azure Service Bus integration to deliver document workflow state transitions to our clients as third-party consumers.

To read more about these messaging services and the purpose of each one, visit the Microsoft product documentation here.

Important: To use these services please contact your Janison account manager to assist with the setup requirements.

Types of messaging

Clients can receive two categories of messages; document workflow state transitions and test delivery messages.

If event hub and/or service bus is configured, then messages are sent when:

  • Taking a test
  • Workflow state changes, if the workflow state transition is configured to send notifications.

Configure Event Hub and/or Service Bus

Event Hub and Service Bus need to be configured at the tenant level. This task should be undertaken by experienced admins only. Your Janison account manager will facilitate this configuration. 

Navigate to Settings > Tenant Settings and open the Event Settings expandable.

The following configuration settings are an example of how this could look. 

Note: The Janison operations team will provide the configuration settings for this page.

Events are identical for Event Hub and Service Bus and are based on test attempt actions and configured workflow transitions. These topics are detailed above.

Service Bus can be used independently or in conjunction with Event Hub and vice versa.

Azure Event Hub

Event Hub is a big data streaming platform and event ingestion service. Read more.

Azure Service Bus

Service Bus is a fully managed enterprise message broker with message queues and publish-subscribe topics. Read more.

Let’s take a closer look at the options available for each category.

Document workflow state transitions

You will need to activate these options at the global tenant level.

Navigate to Settings > Workflow definitions.

Select  the relevant workflow. In the below example, we’ve selected the Assessment Event Workflow.

For any tenant that has an Event Hub and/or Service Bus connection configured (see below for config), then enabling notifications for a specific workflow transition will trigger a notification to be sent when that workflow transition is triggered.

To enable the options, go into edit mode and make your selections in the Notifications column and Save.

Workflow state transition event messages have the following structure:

				
					{
  Id: "54283202-1004-4D32-B730-9F28E4F8C238",
  Entity: "AssessmentEvent",
  Event: "DocumentStateTransition",
  TransitionFrom: "Draft",
  TransitionTo: "Delivery",
  TransitionName: "Commence Delivery"
}
				
			

Workflow state transition payload definition

PropertyDescription
IDstring (36). System assigned unique identifier of the entity being transitioned
Entitystring (128). Name of the entity type being transitioned, possible values are defined in workflow definitions (/admin/workflow/index)
Eventstring(64). Will always be ‘DocumentStateTransition‘ for workflow state transition messages
TransitionFromstring(128). Name of the workflow state transition being transitioned from
TransitionTostring(128). Name of the workflow state transition being transitioned to
TransitionNamestring(128). Name of the workflow state transition being triggered

Test delivery messages

Admins can configure test delivery messages to send notifications at a tenant level.

Navigate to Settings > Tenant Settings. 

Open the Event Settings expandable to view the available notifications.

Enable Login Confirmation – If this is enabled, a ‘login’ confirmation will be included in the event message when a user confirms their identity upon login.

Enable Start Confirmation – If this is enabled, a ‘start’ confirmation will be included in the event message when a user enters the main body of a test for the first time.

Enable First Start Confirmation – a message is sent when main body of a test is entered for the first time. Whilst similar to start, this is only sent once per assessment event enrolment.

Enable Submit Confirmation – If this is enabled, a ‘submit’ confirmation will be included in the event message when an attempt is submitted by the user or admin.

Additional Submit Confirmation Items – If added here, item custom attributes can be included in the ‘submit’ confirmation messages when an attempt is submitted by the user or admin.

To be available for the selection, custom attributes need to be linked directly to the item and be one of the following types: boolean, integer, float, string, list, date

Enable Reopen Confirmation – If this is enabled, a ‘reopen’ confirmation will be included in the event message when an attempt is reopened by the user or admin.

Any tenant that has an event hub and/or service bus connection configured will send messages for any configured test player events. See example message payloads below.

Login, Start, Reopen

				
					{
  Id: "54283202-1004-4D32-B730-9F28E4F8C238",
  Entity: "TestAttempt",
  Event: "Login"
}
				
			

Payload Definition

PropertyDescription
Idstring (36). System assigned unique identifier of the test attempt.
Entitystring(64). Always ‘TestAttempt’ for test delivery messages
Eventstring (64). Type of event being triggered available values Login, Start or Reopen

First Start

				
					{
    "Id": "4e96cd9e-2dc8-ed11-a000-ec086b08fe56",
    "Entity": "TestAttempt",
    "Event": "FirstStart",
    "DateStarted": "2023-03-24T00:01:17.0997404Z",
    "OrgUnitId": "7cd8f2cd-498d-ec11-991b-acb30ea8de22",
    "OrgUnitIdentifier": "oup-organisation-guid",
    "GroupId": "7e9065a8-6b40-ee11-b727-00155df53dae",
    "AssessmentEventId": "8510459a-a50c-ec11-862c-b38465c83433"
} 
				
			

Payload definition

PropertyDescription
Idstring (36). System assigned unique identifier of the test attempt.
Entitystring(64). Always ‘TestAttempt’ for test delivery messages
Eventstring (64). Type of event being triggered available values FirstStart
DateStartedstring (28). UTC date string of when attempt was started.
OrgUnitIdstring (36). System assigned unique identifier of the org unit linked to the test attempt. Org unit where attempt is taken. If not set value will be null.
OrgUnitIdentifierstring (510). User assigned unique identifier of the org unit linked to the test attempt. If not set value will be null.
GroupIdstring (36). Unique identifier of the group linked to the test attempt. Set when attempt is created from a group enrolment. If not set value will be null.
AssessmentEventIdstring (36). Unique identifier of the assessment event linked to the test attempt.

Submit
Example with just 1 question.

				
					{
	"DateStarted": "2023-07-12T23:26:57.4951063Z",
	"DateCompleted": "2023-07-12T23:27:32.4786313Z",
	"AnswerScores": [
		{
			"QuestionId": "58a040cf-880f-ec11-9a18-38baf811fd72",
			"Score": 1,
			"MaxScore": 1,
			"Response": "00101",
			"QuestionData": {
				"question-no": "1"
			}
		}
	],
	"Score": 1,
	"MaxScore": 1,
	"Id": "a33fe07a-0b21-ee11-b714-f4267980d21f",
	"Entity": "TestAttempt",
	"Event": "Submit"
}
				
			

Payload Definition

PropertyDescription
Idstring (36). System assigned unique identifier of the test attempt.
Entitystring(64). Always ‘TestAttempt’ for test delivery messages
Eventstring (64). Type of event being triggered available values Login, Start or Reopen
DateStartedstring (28). UTC date string of when attempt was started.
DateCompletedstring (28). UTC date string of when attempt was completed.
Scoredouble. Sum of answer scores for attempt will be null if the attempt is not fully marked.
MaxScoredouble. Maximum achievable score for the attempt.
AnswerScoresarray of AnswerScore. Array of answer details for all markable main body question in the attempt.

AnswerScore Payload Definition

PropertyDescription
QuestionIdstring (36). System assigned unique identifier of the question linked to the answer.
Scoredouble. Score awarded for answer, null if not marked.
MaxScoredouble. Maximum achievable score for the answer.
Response

string. Users raw answer. Only returned for the following question types:

  • multiple choice – string with selected choice eg “3”
  • multiple choices – string of selected choices eg “01001”
  • keyword – entered answer text

All other question types return null

QuestionDataobject. An object containing a collection of key value pairs as defined in Additional Submit Confirmation Items. Will return null if no Additional Submit Confirmation Items are configured or if the question contains no data for the configured items.

Consuming Service Bus\EventHub Messages

Service Bus

The following details will be provided by client manager after being received from the operations team:

  • Connection string: connection string details for listen access to service bus queue
  • Queue name: name of queue

Code example

Install the Azure.Messaging.ServiceBus NuGet package.

Use the following C# code example to receive messages added to the queue.

				
					using Azure.Messaging.ServiceBus;
using System;
using System.Threading.Tasks;

namespace ServiceBus.Testing
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            // Replace with your Service Bus connection string and queue name
            string connectionString = "your-connection-string";
            string queueName = "your-queue-name";

            // Create a ServiceBusClient
            ServiceBusClient client = new ServiceBusClient(connectionString);
            // Create a ServiceBusReceiver to receive messages
            ServiceBusReceiver receiver = client.CreateReceiver(queueName);

            Console.WriteLine("Listening for messages...");

            try
            {
                while (true)
                {

                    // Receive a batch of messages (adjust the max messages and max wait time as needed)
                    var messageBatch = await receiver.ReceiveMessagesAsync(
                        maxMessages: 10, // Adjust as needed
                        maxWaitTime: TimeSpan.FromSeconds(60)); // Adjust as needed

                    foreach (ServiceBusReceivedMessage m in messageBatch)
                    {
                        try
                        {
                            // Process the message here
                            Console.WriteLine($"Received message: {m.Body}");

                            // Complete the message to remove it from the queue
                            await receiver.CompleteMessageAsync(m);
                        }
                        catch (Exception)
                        {
                            // Moves message to dead-letter queue if processing fails
                            // Dead-letter messages can be processed from the dead-letter queue later
                            // To access messages from the dead-letter queue, 
                            // create a receiver using the ServiceBusOptions.DefaultReceiveMode = ReceiveMode.DeadLetter in the CreateReceiver() method
                            await receiver.DeadLetterMessageAsync(m);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}");
            }

            // Remember to manually dispose of the objects when done
            await receiver.CloseAsync();
        }

    }

}
				
			

Event Hub

The following details will be provided by client manager after being received from the operations team:

  • Connection string: connection string details for listen access to the event hub
  • Event hub name: name of the event hub

Code example

Install the Azure.Messaging.EventHubs NuGet package.

Install the Azure.Messaging.EventHubs.Processor NuGet package.

Install the Azure.Storage.Blobs NuGet package.

Use the following C# code example to receive event added to the hub. To use this code an Azure.Storage account is required to hold checkpoint information.

				
					using Azure.Messaging.EventHubs;
using Azure.Messaging.EventHubs.Consumer;
using Azure.Messaging.EventHubs.Processor;
using Azure.Storage.Blobs;
using System;
using System.Text;
using System.Threading.Tasks;
class Program
{
    static async Task Main(string[] args)
    {
        string eventHubName = "your-event-hub-name";
        string connectionString = "your-event-hub-connection-string";
        string storageConnectionString = "your-storage-connection-string";
        string storageContainerName = "your-storage-container-name";

        BlobContainerClient storageClient = new BlobContainerClient(storageConnectionString, storageContainerName);
        // Create an event processor client to process events in the event hub using the default consumer group
        var processor = new EventProcessorClient(
            storageClient,
            EventHubConsumerClient.DefaultConsumerGroupName,
            connectionString,
            eventHubName);

        // Register handlers for processing events and handling errors
        processor.ProcessEventAsync += ProcessEventHandler;
        processor.ProcessErrorAsync += ProcessErrorHandler;

        Console.WriteLine("Starting the event processor...");
        // Start the processing events will continue to be received until the processor is stopped
        await processor.StartProcessingAsync();

        Console.WriteLine("Press any key to stop the processor...");
        Console.ReadKey();

        Console.WriteLine("Stopping the event processor...");
        await processor.StopProcessingAsync();
    }

    private static async Task ProcessEventHandler(ProcessEventArgs eventArgs)
    {
        try
        {
            // Perform the application-specific processing for an event
            Console.WriteLine("\tReceived event: {0}", Encoding.UTF8.GetString(eventArgs.Data.Body.ToArray()));
            // update the checkpoint in the blob storage so that the app receives only new events the next time it's run
            await eventArgs.UpdateCheckpointAsync();
        }
        catch
        {
            // Handle the exception from handler code
        }
    }

    private static Task ProcessErrorHandler(ProcessErrorEventArgs eventArgs)
    {
        try
        {
            // Perform the application-specific processing for an error
            Console.WriteLine($"\tPartition '{eventArgs.PartitionId}': an unhandled exception was encountered. This was not expected to happen.");
            Console.WriteLine(eventArgs.Exception.Message);
        }
        catch
        {
            // Handle the exception from handler code;
        }
        return Task.CompletedTask;
    }
}

				
			

Topics on this page