Imagine that you are part of an organization where your colleagues are either dispersed across a region or across the globe.
PairUp is an automation solution deployed in Azure that will pair Azure FastTrack colleagues together to catch up and expand their network. As the system is completely automated there are several must haves to make this an efficient process that's able to scale as more people are added to an organization but can also be extended to other regions.
Here's a short summary of what PairUp does:
As a team we came up with the following design principles:
The whole solution was developed in Azure and for that purpose we used various components, as you can see in the following figure:
Figure 1 - Architecture Components
Regarding the compute components, the orchestration of the whole business logic was implemented using logic apps, to keep the coding part of the solution to a minimum and follow a K.I.S.S. approach. We also used parameterized options to be able to scale to other regions and different organizations and we tried to break complex steps to multiple logic apps for maintainability. We just kept the complex pairing logic algorithm inside an Azure Function. Logic apps are using various connectors to integrate with other Azure components, like:
For monitoring purposes, we used Azure Monitor and in particular Application Insights, especially for gathering logs from the executions of the pair matching algorithm, through Azure Functions.
The solution was deployed into three different environments: Sandpit, UAT and Production. In the Sandpit environment, we deployed everything manually through the Azure portal and we initially developed and tested our solution there. After having a stable solution, we then used the UAT and Production environments to deploy the finalized components. This was done through Azure DevOps Server (ADO) pipelines, that were written in yaml files and through leveraging custom JSON Azure Resource Manager (ARM) templates, to fully comply and follow Continuous Integration / Continuous Deployment (CI/CD) and Infrastructure as Code (IaC) principles. All those files are kept into GIT source control in ADO.
Based on the Cloud Adoption Framework (CAF) naming convention guidelines, the names of the resources follow the below rule:
Logic apps include a step number which will go from 000, 010, 020 etc, to allow us to interleave missing steps.
Storage or any other resource that doesn't support - in the name, we will skip the ‘-‘ characters, for example, our UAT storage is called pueustg01.
Figure 2 - Azure Resources
For storing the state of our solution, we used the Table Storage Service of a newly provisioned Azure Storage Account, and we defined the following “tables”:
The workflow of the PairUp at a very high level contains four main steps as you can see in the image below.
Figure 3 - PairUp Workflow
We will discuss each step in the following sections.
The first step is to populate the Users table, which will be our user base for the PairUp rounds. We need to send out emails to all potential participants, but to do that we need to know who they are. To do this, a Logic App called pu-e-u-s000-populate-user-table runs, deletes all previous entries in the Users table, and eventually uses the Graph API connector to do a REST API call to list everyone who is a direct report of a top-level manager in the organization. The manager alias is a parameter that is passed into the Logic App. The Graph API call returns the necessary user information list and from that we are populating our Users list once again using a recursion mechanism. This step is an asynchronous one and happens once every week, to be able to account for people who join or leave the organization. You can see a detailed view of the workflow followed in the image below.
Figure 4 - pu-e-u-s000-populate-user-table & pu-e-u-s000-populate-user-table-recursion-XX logic apps flow
The pu-e-u-s000-populate-user-table logic app relies to a couple of other logic apps:
These two logic apps are HTTP trigger based (they are modelled through the “Process User” part seen in Figure 4) and essentially have the responsibility of traversing the list of direct reports recursively, starting with the top-level manager of the organization. In our implementation the code base for these logic apps is identical (deploy the same ARM template for both Azure resources).
Now that we have all the user details from the organization we want to target, the next step is to provide a registration process to sign up for the next PairUp round. A Logic App called pu-e-u-s010-initialize-pairing-round, starts at 8:00 (UTC+00:00) on Monday every 4 weeks and firstly initializes the next pairing round and saves it in the Rounds list. It then reads all users saved inside the Users list from the “Populate users” step, and for each of these users, it calls an HTTP trigger-based logic app called pu-e-u-s010-request-single-user-to-enroll. This logic app has the responsibility to fetch the details of the user from the “Users” list and sends out an adaptive card.
Figure 5 - pu-e-u-s010-initialize-pairing-round & pu-e-u-s010-request-single-user-to-enroll logic apps flow
The card contains a button embedded. When the user clicks it, then he / she is being automatically added to the RoundRegistrations list and is an active registrant of the current pairing round.
Figure 6 - User registers for this pairing round
The result of the above steps is a registration email sent to each user in the organization. The flow expires after 3 days, which means that users won't be able to register after this deadline.
With the users that want to participate for the current round having already registered, it's time for PairUp to match them together. To do that though we need to make sure the following constraints are being met:
The above pairing algorithm logic is implemented in an Azure Functions App and is triggered by another logic app called pu-e-u-s020-compute-pairs. This logic app runs at 10:00 AM (UTC+00:00) on Thursday every 4 weeks. This is 3 days and 2 hours after the user registration flow has been triggered, which means that participants have 3 days in total to register for the current round. The Function App does the following things:
In a high level, the actual pairing algorithm works as follows:
Figure 7 - Select user to pair
After the Function App logic has finished its job, the pu-e-u-s020-compute-pairs logic app continues its execution by triggering another HTTP based logic app called pu-e-u-s020-schedule-meetings, that orchestrates the meeting invitation scheduling process.
The scheduling Logic App reads through the Pairings list, and for each pairing, it sends out an email invitation template to both users, with Cortana in CC. The body of the email template asks Cortana to automatically schedule a call at a mutual time within the next week.
Figure 8 - Send meeting invitations
The result of the above steps is the generation of two different emails. The first one is of the pairing email that is being sent to both pairing participants, with Cortana in CC. The second one is the actual meeting invitation sent by Cortana Scheduler to both paired persons.
The last part of the PairUp process is the feedback request from all participants in the current round. This is done by, yet another logic app called pu-e-u-s030-request-user-feedback. This is also a time triggered one and is being run at 8:00 AM (UTC+00:00) on Monday every 4 weeks.
Whenever it gets triggered, it first calls another function app called GetFeedbackRound, which returns from the Rounds list, the current PairUp round, where no feedback emails are yet sent to the round participants. The logic app then fetches from the Pairings list the total pairings for the current round and for each pairing it sends the actual feedback email to each pair participant.
Figure 9 - Feedback round
As far as ALM and DevOps are concerned, the whole infrastructure and source code builds and deployments for the PairUp system are being processed in Azure DevOps (ADO) inside a dedicated Project called PairUp. Using the principles of CI/CD and IaC, the solution is fully automated and uses the following dedicated pipelines:
Figure 10 - Azure DevOps Pipelines
All above pipelines are implemented using yaml files that are being kept inside source control inside a dedicated folder called “devops”, along with the source code (“src” folder), tests (“tests” folder) and documentation (“wiki” folder) of the entire solution.
Figure 11 – Project Folder Structure
The infrastructure of the solution is being developed using ARM template JSON files, that are used by the PairUp-Infrastructure pipeline, to deploy everything needed as Azure resources, to run the whole system.
Figure 12 - Infrastructure ARM template json files
To provision the infrastructure, we use the PairUp-Infrastructure pipeline, which runs automatically after every commit that is merged in the main branch, only for the changes in the paths that you can see in the following figure:
Figure 13 - PairUp Infrastructure Pipeline Trigger Paths
The pipeline, in general, implements the steps below in three separate stages:
The provisioning of the infrastructure in the UAT environment is being done automatically. On the other hand, in the Production environment there is a manual approval mechanism set, that blocks the deployment, until a member of the admin security group reviews and explicitly approves it.
Figure 14 - PairUp Infrastructure Pipeline Stages
The “business logic” of our logic apps and things like triggers, actions and outputs are being kept also in JSON files and stored in source control under src/logic-apps folder. These JSON files are being used by the PairUp-LogicApps ADO pipeline, which deploys the app code in the logic apps provisioned in the resource group from the infrastructure pipeline.
To deploy the code, we use the PairUp-LogicApps pipeline, which runs automatically after every commit that is merged in the main branch, only for the changes in the paths that you can see in the following figure:
Figure 15 - PairUp Logic Apps Pipeline Trigger Paths
The pipeline, in general, implements the steps below in three separate stages:
Figure 16 - PairUp Logic Apps Pipeline Stages
Inside the src/logic-apps/html-templates folder, we can also find the HTML templates that are being used to compose the various email bodies that the PairUp workflow sends, like registration, meeting schedules and feedback requests.
For the templates we only read the internal HTML, after the `<!-- START TEMPLATE -->` comment up to the `<!-- END TEMPLATE -->` comment.
To extract the HTML, we use the following command:
Figure 17 - Command to extract the HTML from a template
The function app contains the logic of the pairing algorithm for the PairUp workflow, the source code of which can be found inside the src/function-apps folder.
To deploy the code, we use the PairUp-FunctionApp pipeline, which runs automatically after every commit that is merged in the main branch, only for the changes in the paths that you can see in the following figure:
Figure 18 - PairUp Function Apps Pipeline Trigger Paths
The pipeline, in general, implements the steps below in three separate stages:
Figure 19 - PairUp Function Apps Pipeline Stages
In all cases, the deployment in the UAT environment is being done automatically. On the other hand, in the Production environment there is a manual approval mechanism set, that blocks the deployment, until a member of the admin security group reviews and explicitly approves it.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.