5.2 Technical Details
5.2.3 JavaScript Event-Processing
JavaScript does not support the inline definiton of triggers and outputs like Java or C#. This means that these have to be defined in a separate file called function.json for every function.
The parameters developers have to define are very simmilar to the ones one has to define in the attributes/annotations because the function.json file is required for deploying to Azure Functions.
On the other platforms these files are just generated from the annotations during the build pro- cess [Mic18a]. Writing the functions configuration can be tedious. Missing code completion in these files makes the implemantation very time intensive because developers always have to look at the documentation in order to find out how they have to specify something. In Java and C# there is code completion for the annotatations making this step way easier. But sometimes it is still necessary to look at the documentation. Subjectively speaking the definiton through annotatations felt way easiser and more intuitive compared to writing the function.json file. An example of the function.json
file can be seen in Listing A.7. The funtion shown here is a very basic HTTP function producing a request from a response with no other service dependencies [Mic18a; Mic18b]. More precisely, this listing shows the function.json for the list function. This important because we do not mention
the required access to the MySQL database in this definiton. Access to the MySQL database has to be ensured by the developer in code. To get access to the mandatory credentails developers must ensure the credentials for the MySQL database are in the local.settings.json, since all values
defined in this configuration file are also mounted as environment variables within the functions environment, the configuration of the MySQL client is identical to AWS depending on the names chosen developers might have to change the names of the accessed environment variables [Kos18]. However the great thing about the JavaScript portion is the fact that we do not need to import any vendor specific APIs in order to interact with the topics and queues. This is achieved by just pushing the message into an array, for sending multiple messages or by setting the value of a variable, for one message [Mic18b; Mic19a]. Everything else will be handled by the runtime. But requiring no external libraries does not imply the freedom to execute the function somewhere else
5 Implementation on Microsoft Azure
of course. Since this the function is still tightly coupled to the runtime environment. However it makes the emulation of the runtime environment easier because mocking the data structures behind the parameters is easier compared to mocking an entire library.
Apart from that Azure does not allow the definiton of multiple functions in one file like it is possible with AWS. Every Function has to be placed in a separate directories with its corresponding function configuration (function.json). According to the documentation it is possible to share code through
separate folders [Mic19a]. However this was not necessary for our implementation since we did not have complicated any shared methods.
Function AWS Azure
Ingest 35 25
Format 21 13
Insert in DB 24 22
List 21 24
Latest 21 24
Table 5.2: Comparison of code sizes of the JavaScript functions for AWS Lambda and Azure
Functions
Taking a look at the AWS Implementation of a format function in AWS Lambda shown in List-
ing A.3 we can identify the code shown in Listing A.4 as reusable12. This code snippet can also be found in the Azure version of the function shown in Listing 5.4. When comparing the two snippets from Azure and AWS side by side, it can be observed that the implementation on AWS is longer, in terms of lines of code, than the Azure version. This seems to be pretty consistent across functions writing to message queues and topics implemented in JavaScript as shown in Table 5.2. For the other functions the code size of the Azure version can actually be longer than the one on AWS. Due to the very small code size of all the functions implemted for this use case the real program logic is very small and does not really count into the size of the function. For example the only vendor unspecific logic in the ingest function is the if statement finding out what type of event
was received.
Unlike the previeous use cases this use-case uses more than a storage account. As a result the creation of the resources for the Event-processing use-case have to be created. To make the function executable we must also ensure the credentials are set in the local.settings.json to allow local
execution and the deployment to Azure. For Azure supports the automated creation of services using the Azure Resource Manager, this work does not use these techniques for Azure. Instead the Azure CLI in combination with Bash is used to create the resources for this use-case. Creating the resources needed and accessing the connection strings is simple using the CLI. The biggest challenge is the automated creation of the local.settings.json this procedure was automated using the jq13
utility and the Azure CLI. After the creation of all the resources the functions can be deployed by running func azure functionapp publish $FUNCTION_APP_NAME -o where $FUNCTION_APP_NAME
represents the name of the Function App on Azure. To ensure the local.settings.json is uploaded
to Azure the -o flag must be passed to the Azure Functions Core Tools CLI.
12Message concatenation in the code sample has been ommited to improve the readability of the code. 13https://stedolan.github.io/jq/
5.2 Technical Details
Listing 5.5 Part of the orchestration function for the matrix multiplication use-case
1 [FunctionName("OrchestrateMatrixMultiplication")]
2 public static async Task<Matrix> OrchestrateMultiplication( 3 [OrchestrationTrigger] DurableOrchestrationContext context
4 ) {
5 var size = context.GetInput<string>();
6 MatrixCalculation c = await context.CallActivityAsync("GenerateMatrix", size);
7 Matrix result = null;
8 if (int.Parse(size) < 10)
9 result = await context.CallActivityAsync<Matrix>("SerialMultiply", c);
10 else
11 // Has been ommitted
12 return result;
13 }
14