PAYG financial services: coming to a bank near you
You walk into your neighborhood bank to see about a mortgage. You and your spouse have your eye on the perfect 3BR, 2BA brick ranch near your child's school, and it won't be on the market long. An hour later, you burst through the front door with a bottle of champagne: "We're qualified!"
The above scenario is possible now through serverless functions, which enable your SAS Viya applications to take input from end users, score the loan application, and return results.
The rest of this post gets into the nitty gritty of serverless functions and SAS Viya, detailing what happens in a bank's computers after a customer applies for a loan. The qualification process starts by running a previously built scoring model to generate a score. You will see how the combination of REST APIs in SAS Viya, analytic models and the restaf library make the task of building the serverless function relatively simple.
The blog titled "SAS REST APIs: a sample application" demonstrated building a SAS Viya application using REST APIs, SAS Visual Analytics and SAS Operational Research. This is typical web applications with application server and SAS Viya running on premise.
If you are one of many users using(or considering) a cloud provider, serverless functions is an useful alternate way to deliver your applications to your users. This eliminates the need to manage the application server associated with your application. Additionally you get zero administration and auto-scaling among other benefits. Many SAS applications that respond quickly to user requests are ideal candidates to be deployed as serverless functions.
The example in this article is available on SAS software’s GitHub site in the viya-apps-serverless-score repository. If you want to see the end application for frame of reference, see the Using the serverless functions section at the bottom of this article. I have also written a separate article: GraphQL and SAS Viya applications - a good match, covering a similar application-building scenario with GraphQL.
Let’s begin with a bit of background on serverless computing and then dig into the details of the application and functions.
Serverless computing explained
The benefits of serverless functions as touted by AWS serverless, Azure and serverless.com:
AWS Lambda
AWS Lambda lets you run code without provisioning or managing servers. You pay only for the compute time you consume– there is no charge when your code is not running. With Lambda, you can run code for virtually any type of application or backend service – all with zero administration. Just upload your code and Lambda takes care of everything required to run and scale your code with high availability. You can set up your code to automatically trigger from other AWS services or call it directly from any web or mobile app.
What is serverless computing?
According to Azure serverless computing is the abstraction of servers, infrastructure, and operating systems. When you build serverless apps you don’t need to provision and manage any servers, so you can take your mind off infrastructure concerns. Serverless computing is driven by the reaction to events and triggers happening in near-real-time—in the cloud. As a fully managed service, server management and capacity planning are invisible to the developer and billing is based just on resources consumed or the actual time your code is running.
Four core benefits of serverless computing from serverless.com:
- Zero administration – Deploy code without provisioning anything beforehand or managing anything afterward. There is no concept of a fleet, an instance, or even an operating system. No more bothering the Ops department.
- Auto-scaling – Let your service providers manage the scaling challenges. No need to fire alerts or write scripts to scale up and down. Handle quick bursts of traffic and weekend lulls the same way — with peace of mind.
- Pay-per-use – Function-as-a-service compute and managed services charged based on usage rather than pre-provisioned capacity. You can have complete resource utilization without paying a cent for idle time. The results? 90% cost-savings over a cloud VM, and the satisfaction of knowing that you never pay for resources you don’t use.
- Increased velocity – Shorten the loop between having an idea and deploying to production. Because there’s less to provision up front and less to manage after deployment, smaller teams can ship more features. It’s easier than ever to make your idea live.
OK, so there is a server involved in serverless computing. The beauty in this technology is that once you deploy your code, you don't have to worry about the underlying infrastructure. You just know that the app should work and you only incur costs when the app is running.
Basic flow
Serverless functions are loaded and executed based on the occurrence of one of the triggers/events supported by the cloud vendor. In this example the API Gateway triggers the serverless functions when an http call invokes the function. The API Gateway calls the handler for the function and passes in the user data. On return from the handler the response is sent to the client. This article focuses on the code inside the Serverless Function box in the picture below.
This example utilizes two key functions:
- app – This function serves up an html application for user to enter the data. This is an example of a web application as a serverless function.
- score – This function takes user input from the web app, executes scoring on a Viya Server and returns the results.
Serverless.yml
The serverless.yml defines the serverless functions and the handlers, used to execute and other system related information. We will focus only on the application specific information.
The code snippet below shows the definition of the path and handler for the two functions in the serverles.yml file.
functions: app: handler: src/app.app events: - http: path: app method: get cors: origin: '*' request: parameters: paths: id: true score: handler: src/score.score events: - http: path: score method: post cors: origin: '*' |
The functions(app & score) in the yaml define:
- event - http event will trigger this function
- path - this is path to the function - similar to what you define in Express or hapijs
- method - http standard GET, PUT etc...
- others - refer to the cloud vendor's documentation for other available options.
The serverless.yml file also sets application related information using environment variables. In this particular use case we define how to access SAS Viya and which scoring model to use.
environment: # # Information for logging into SAS Viya # VIYA_SERVER: http://example.viya.server.com CLIENTID: raf CLIENTSECRET: raf USER:rafuser PASSWORD: rafpass # # astore to be used for scoring # caslib: casuser name: GRADIENT_BOOSTING___BAD_2 |
A note on securing your password
In this example we store the userid and password in environment variables. This is to the keep the focus on the internals of serverless functions for SAS Viya. Locally you can use "serverless variables" to secure the information during development. However, for production deployment, refer to your provider's recommendations and the user community for best practices.
Sounds like a followup blog in the future 🙂
Anatomy of the serverless function
Figure 2 shows the flow inside the serverless function for this example. This pattern will repeat itself in your serverless functions.
Serverless function score
The code below is the handler for the score function. The rest of this section will discuss each of the key features of the handler.
// // See src/score.js for the full code // module.exports.score = async function (event, context ) { let store = restaf.initStore(); /* initialize restaf */ let inParms = parseEvent(event); /* get user input */ let payload = getLogonPayload(); /* get logon information */ return store.logon(payload) /* logon to SAS Viya */ .then (() > scoreMain( store, inParms )) /* score */ .then(result > setPayload(result)) /* return results */ .catch(err > setError(err)) /* else return errors */ } |
Step 1: Parse the input
The event parameter contains the input from the caller (web application, another serverless function, etc).
The content of the event parameter is whatever the designer of the serverless function desires. In this particular case, a sample event data is shown below.
{ "input": { "JOB" : "J1", "CLAGE" : 100, "CLNO" : 20, "DEBTINC": 20, "DELINQ" : 2, "DEROG" : 0, "MORTDUE": 4000, "NINQ" : 1, "YOJ" : 10, "LOAN" : 10000, "VALUE" : 1000000 } } |
The parseEvent function validates the incoming information.
module.exports = function parseEvent(event) let input = null; let body = {}; let rstore = { caslib: process.env.ASTORE_CASLIB, name : process.env.ASTORE_NAME } if ( event.body != null ) { body = ( typeof event.body === 'string') ? JSON.parse(event.body) : Object.assign({}, event.body); if ( body.hasOwnProperty('input') === true ) { input = body.input; } return { rstore: rstore, input: input } } |
Step 2: Logon to SAS Viya
The server.yml defines the SAS Viya logon information. Note there are other secure ways to manage sensitive information like passwords. You should refer to your provider’s documentation.
module.exports = function getLogonPayload() { let p = { authType : 'password', host : `${process.env.VIYA_SERVER}`, user : process.env['USER'], password : process.env['PASSWORD'], clientID : process.env['CLIENTID'], clientSecret: (process.env.hasOwnProperty('CLIENTSECRET')) ? process.env[ 'CLIENTSECRET' ] : '' }; return p; } |
The line restaf.logon(payload) in function in the handler code logs on to the SAS Viya Server using this information.
Step 3 and Step 4: Create Payload and make REST API calls
On successful logon the server is called to do the scoring. This particular example uses the sccasl.runcasl method to run CAS Language (CASL) statements and return the scores. Creating the score has two steps:
- upload user input: The user input is converted to a csv and uploaded to a CAS table
- Submit CASL statements to SAS Viya (CAS) to do the scoring
The code in src/scoreMain in the repository accomplishes both these steps.
Each of these steps use a CAS action:
-
- table.upload – to upload the user data into a CAS Table. The input data is converted into a comma-delimited file(csv) and then uploaded. The REST call using restaf looks like this:
let csv = makecsv(input); /* create a csv */ let JSON_Parameters = { casout: { caslib : 'casuser', /* a valid caslib */ name : 'INPUTDATA', /* name of output file on cas server */ replace: true }, importOptions: { fileType: 'csv' /* type of the file being uploaded */ } }; let payload = { headers: { 'JSON-Parameters': JSON_Parameters }, data : csv, action : 'table.upload' }; let result = await store.runAction(session, payload); |
-
- sccasl.runcasl – execute CASL statements to do the scoring
// Setup casl statements let caslStatements = ` loadactionset "astore"; action table.loadTable / caslib = "${rstore.caslib}" path = "${rstore.name}.sashdat" casout = { caslib = "${rstore.caslib}" name = "${rstore.name}" replace=TRUE}; action astore.score / table = { caslib= 'casuser' name = 'INPUTDATA' } rstore = { caslib= "${rstore.caslib}" name = '${rstore.name}' } out = { caslib = 'casuser' name = 'OUTPUTDATA' replace= TRUE}; action table.fetch r = result/ format = TRUE table = { caslib = 'casuser' name = 'OUTPUTDATA' } ; send_response(result); `; // execute cas actions payload = { action: 'sccasl.runcasl', data : { code: caslStatements} } result = await store.runAction(session, payload); |
Step 5: Create response
AWS serverless functions must return data and error(s) in a certain form. The two functions setPayload.js and setError.js accomplish this.
module.exports = function setPayload (body) { return { "statusCode": 200, "headers" : { 'Access-Control-Allow-Origin' : '*', 'Access-Control-Allow-Credentials': true }, "isBase64Encoded": false, "body" : JSON.stringify(body) } } |
Using the serverless functions
When the serverless function is deployed you will get a link for each of the functions. In our case we receive the request shown below (with xxxx replaced with appropriate information).
GET - https://xxxx.amazonaws.com/demo/app |
The first link serves up the web application. The user enters some values and the app calls the score serverless function to get the results.
Alternatively, you can write your own application and make an http POST call to the score function using a link such as:
POST - https://xxxx.amazonaws.com/demo/score |
To invoke the web application, you will visit the link
https://xxxx.amazonaws.com/demo/app |
with your browser. You should see a display shown in Figure 3:
Entering values into the two fields and pressing Submit calls the second serverless function, score, and results in a pie chart as seen in Figure 4:
Please see the loan.html file in the GitHub repository for details on the application. Displayed below is the relevant part of the Javascript in the loan.html. The score-function-url is the url for the score function. The payload was described earlier in this article. The http call is made using axios.
async function runScore(inputValues ){ let payload = { astore: { caslib: 'Public', name: 'GRADIENT_BOOSTING___BAD_2' }, input: inputValues } let config = { url: {score-function-url} method: 'POST', data: payload } let r = await axios(config); return r.data.score; } |
Porting to other cloud providers
The cloud provider dependent information is handled in the following functions: score.js, parseEvent.js, setPayload.js and setError.js. The rest of the code is host agnostic. In writing your own functions the recommendation is to follow the same pattern as much as possible. The generic code is then available in its own repository for reuse with other providers and applications.
Go try it yourself
I have shown you how to deliver your SAS Viya applications as serverless functions. To access more examples please see the GitHub restaf-demos repository.
Supporting Resources
- The tools from serverless.com are quite useful. They allow you to develop and test the functions locally and then deploy them when ready.
- Refer to this introductory tutorial for step-by-step instructions on building an application in a serverless framework with Node.js.
6 Comments
Hi Deva,
You mention Model Manager has the ability to publish to Docker Containers. What is the latest progress on this? Does SAS have any examples of this being used on AWS Lambda?
Andrew: SAS Container Runtime(SCR) is a docker container that can run models. It works on all the major cloud providers. Please see this link
Hi Deva, great blog thanks. I do have a question and maybe I'm missing something here. What I am not able to understand is the following. So if we are using VIYA to score that would imply that a VIYA instance is required with at least a "minimum' footprint VIYA in order to run the score code right? That would mean that when a serverless request is made a VIYA instance is instantiated to run the score code? Is this a VIYA container? It may not be practical in a real-time requirement to spin a VIYA instance up and down every time a scoring request is made? Can you please provide some insight for me?
Gerrit:
Thanks for your comment.
The "current" expectation is that the Viya Server is running either on-premise or on a cloud provider( in my case AWS). It is an alternative to maintaining an app server to host the scoring application.
The newly announced SAS Open Model Manager -(https://www.sas.com/en_us/software/open-model-manager/features-list.html) can publish models to a docker container. It would be interesting to investigate the use of serverless functions with these models in the container.
Cheers...
Deva
Other than schlepping usernames and passwords across the Internet as environment variables what would you recommend as a security best practice?
Satoshi: This link is a good place to start: https://docs.aws.amazon.com/lambda/latest/dg/tutorial-env_console.html.
Would be interested in hearing about your experience with Serverless functions.
Cheers..
Deva