Scott Hanselman

What is Serverless Computing? Exploring Azure Functions

August 27, '16 Comments [40] Posted in Azure | nodejs
Sponsored By

There's a lot of confusing terms in the Cloud space. And that's not counting the term "Cloud." ;)

  • IaaS (Infrastructure as a Services) - Virtual Machines and stuff on demand.
  • PaaS (Platform as a Service) - You deploy your apps but try not to think about the Virtual Machines underneath. They exist, but we pretend they don't until forced.
  • SaaS (Software as a Service) - Stuff like Office 365 and Gmail. You pay a subscription and you get email/whatever as a service. It Just Works.

"Serverless Computing" doesn't really mean there's no server. Serverless means there's no server you need to worry about. That might sound like PaaS, but it's higher level that than.

Serverless Computing is like this - Your code, a slider bar, and your credit card. You just have your function out there and it will scale as long as you can pay for it. It's as close to "cloudy" as The Cloud can get.

Serverless Computing is like this. Your code, a slider bar, and your credit card.

With Platform as a Service, you might make a Node or C# app, check it into Git, deploy it to a Web Site/Application, and then you've got an endpoint. You might scale it up (get more CPU/Memory/Disk) or out (have 1, 2, n instances of the Web App) but it's not seamless. It's totally cool, to be clear, but you're always aware of the servers.

New cloud systems like Amazon Lambda and Azure Functions have you upload some code and it's running seconds later. You can have continuous jobs, functions that run on a triggered event, or make Web APIs or Webhooks that are just a function with a URL.

I'm going to see how quickly I can make a Web API with Serverless Computing.

I'll go to http://functions.azure.com and make a new function. If you don't have an account you can sign up free.

Getting started with Azure Functions

You can make a function in JavaScript or C#.

Getting started with Azure Functions - Create This Function

Once you're into the Azure Function Editor, click "New Function" and you've got dozens of templates and code examples for things like:

  • Find a face in an image and store the rectangle of where the face is.
  • Run a function and comment on a GitHub issue when a GitHub webhook is triggered
  • Update a storage blob when an HTTP Request comes in
  • Load entities from a database or storage table

I figured I'd change the first example. It is a trigger that sees an image in storage, calls a cognitive services API to get the location of the face, then stores the data. I wanted to change it to:

  • Take an image as input from an HTTP Post
  • Draw a rectangle around the face
  • Return the new image

You can do this work from Git/GitHub but for easy stuff I'm literally doing it all in the browser. Here's what it looks like.

Azure Functions can be done in the browser

I code and iterate and save and fail fast, fail often. Here's the starter code I based it on. Remember, that this is a starter function that runs on a triggered event, so note its Run()...I'm going to change this.

#r "Microsoft.WindowsAzure.Storage"
#r "Newtonsoft.Json"

using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json;
using Microsoft.WindowsAzure.Storage.Table;
using System.IO; 

public static async Task Run(Stream image, string name, IAsyncCollector<FaceRectangle> outTable, TraceWriter log)
{
    var image = await req.Content.ReadAsStreamAsync();
    
    string result = await CallVisionAPI(image); //STREAM
    log.Info(result); 

    if (String.IsNullOrEmpty(result))
    {
        return req.CreateResponse(HttpStatusCode.BadRequest);
    }

    ImageData imageData = JsonConvert.DeserializeObject<ImageData>(result);
    foreach (Face face in imageData.Faces)
    {
        var faceRectangle = face.FaceRectangle;
        faceRectangle.RowKey = Guid.NewGuid().ToString();
        faceRectangle.PartitionKey = "Functions";
        faceRectangle.ImageFile = name + ".jpg";
        await outTable.AddAsync(faceRectangle); 
    }
    return req.CreateResponse(HttpStatusCode.OK, "Nice Job");  
}

static async Task<string> CallVisionAPI(Stream image)
{
    using (var client = new HttpClient())
    {
        var content = new StreamContent(image);
        var url = "https://api.projectoxford.ai/vision/v1.0/analyze?visualFeatures=Faces";
        client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", Environment.GetEnvironmentVariable("Vision_API_Subscription_Key"));
        content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        var httpResponse = await client.PostAsync(url, content);

        if (httpResponse.StatusCode == HttpStatusCode.OK){
            return await httpResponse.Content.ReadAsStringAsync();
        }
    }
    return null;
}

public class ImageData {
    public List<Face> Faces { get; set; }
}

public class Face {
    public int Age { get; set; }
    public string Gender { get; set; }
    public FaceRectangle FaceRectangle { get; set; }
}

public class FaceRectangle : TableEntity {
    public string ImageFile { get; set; }
    public int Left { get; set; }
    public int Top { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }
}

GOAL: I'll change this Run() and make this listen for an HTTP request that contains an image, read the image that's POSTed in (ya, I know, no validation), draw rectangle around detected faces, then return a new image.

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) {
var image = await req.Content.ReadAsStreamAsync();

As for the body of this function, I'm 20% sure I'm using too many MemoryStreams but they are getting disposed so take this code as a initial proof of concept. However, I DO need at least the two I have. Regardless, happy to chat with those who know more, but it's more subtle than even I thought. That said, basically call out to the API, get back some face data that looks like this:

2016-08-26T23:59:26.741 {"requestId":"8be222ff-98cc-4019-8038-c22eeffa63ed","metadata":{"width":2808,"height":1872,"format":"Jpeg"},"faces":[{"age":41,"gender":"Male","faceRectangle":{"left":1059,"top":671,"width":466,"height":466}},{"age":41,"gender":"Male","faceRectangle":{"left":1916,"top":702,"width":448,"height":448}}]}

Then take that data and DRAW a Rectangle over the faces detected.

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    var image = await req.Content.ReadAsStreamAsync();

    MemoryStream mem = new MemoryStream();
    image.CopyTo(mem); //make a copy since one gets destroy in the other API. Lame, I know.
    image.Position = 0;
    mem.Position = 0;
    
    string result = await CallVisionAPI(image); 
    log.Info(result); 

    if (String.IsNullOrEmpty(result)) {
        return req.CreateResponse(HttpStatusCode.BadRequest);
    }
    
    ImageData imageData = JsonConvert.DeserializeObject<ImageData>(result);

    MemoryStream outputStream = new MemoryStream();
    using(Image maybeFace = Image.FromStream(mem, true))
    {
        using (Graphics g = Graphics.FromImage(maybeFace))
        {
            Pen yellowPen = new Pen(Color.Yellow, 4);
            foreach (Face face in imageData.Faces)
            {
                var faceRectangle = face.FaceRectangle;
                g.DrawRectangle(yellowPen, 
                    faceRectangle.Left, faceRectangle.Top, 
                    faceRectangle.Width, faceRectangle.Height);
            }
        }
        maybeFace.Save(outputStream, ImageFormat.Jpeg);
    }
    
    var response = new HttpResponseMessage()
    {
        Content = new ByteArrayContent(outputStream.ToArray()),
        StatusCode = HttpStatusCode.OK,
    };
    response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
    return response;
}

I also added a reference to System. Drawing using this syntax at the top of the file and added a few namespaces with usings like System.Drawing and System.Drawing.Imaging. I also changed the input in the Integrate tab to "HTTP" as my input.

#r "System.Drawing

Now I go into Postman and POST an image to my new Azure Function endpoint. Here I uploaded a flattering picture of me and unflattering picture of The Oatmeal. He's pretty in real life just NOT HERE. ;)

Image Recognition with Azure Functions

So in just about 15 min with no idea and armed with just my browser, Postman (also my browser), Google/StackOverflow, and Azure Functions I've got a backend proof of concept.

Azure Functions supports Node.js, C#, F#, Python, PHP *and* Batch, Bash, and PowerShell, which really opens it up to basically anyone. You can use them for anything when you just want a function (or more) out there on the web. Send stuff to Slack, automate your house, update GitHub issues, act as a Webhook, etc. There's some great 3d party Azure Functions sample code in this GitHub repo as well. Inputs can be from basically anywhere and outputs can be basically anywhere. If those anywheres are also cloud services like Tables or Storage, you've got a "serverless backed" that is easy to scale.

I'm still learning, but I can see when I'd want a VM (total control) vs a Web App (near total control) vs a "Serverless" Azure Function (less control but I didn't need it anyway, just wanted a function in the cloud.)


Sponsor: Aspose makes programming APIs for working with files, like: DOC, XLS, PPT, PDF and countless more.  Developers can use their products to create, convert, modify, or manage files in almost any way.  Aspose is a good company and they offer solid products.  Check them out, and download a free evaluation.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb
Saturday, 27 August 2016 00:29:32 UTC
Functions are incredibly powerfull, We have started using powershell functions to write small Devops tasks that we can trigger via a webhook.. Since Functions has the azure sdk already available, its a great place to host and run cloud functions to manage all of your other cloud assets.
Eric Hexter
Saturday, 27 August 2016 00:39:41 UTC
This is pretty amazing. There is so much choice available right now to solve peoples problems.
Barry
Saturday, 27 August 2016 01:07:45 UTC
Thanks a lot for the article. It's something new to explore for me
Saturday, 27 August 2016 01:27:27 UTC
Great article. I always explain on what is serverless like this, Serverless does not mean there is NO server at the backened. Serverless IS your APP MODEL which is not dependent on any server infrastructure. Azure Functions and Azure Logic Apps is one of the best example of Serverless.
Riza Marhaban
Saturday, 27 August 2016 01:34:06 UTC
but it's higher level than that :-)
Saturday, 27 August 2016 04:22:58 UTC
Yeah, that looks good.
Kevin
Saturday, 27 August 2016 05:13:42 UTC
Sweet!... I have always ignored serverless computing because I find it absurd and too shy to ask. This brief explanation nail it for me.

So what .NET API level is supported? 4.5? 4.62? 2.0?
Rosdi
Saturday, 27 August 2016 05:48:39 UTC
CGI strikes back!
Vladimir
Saturday, 27 August 2016 06:21:03 UTC
In my head this is a webjob, queue, and web API endpoint without all the plumbing.
Jonathan Cardy
Saturday, 27 August 2016 14:44:04 UTC
Please don't tell anyone anywhere you made this in 15 minutes. This took you an hour and another 40 minutes to blog at least; and in human IT worker terms that's 1/2 a day... Nice work, just don't say 15 minutes.
Dane Watson
Saturday, 27 August 2016 16:03:07 UTC
Can you add references to nuget packages?
Karlo Medallo
Saturday, 27 August 2016 16:54:59 UTC
Awesome Scott. Hard to know what solution to use these days, and that's a good thing. I am wondering though, what do we use for a test environment if we go whole hog with this 'functions in the sky' approach? Another test instance on Azure, sure, but anything that I can set up locally on Windows/.Net to have some unit tests running on these functions? I ask out of laziness.
John Walters
Saturday, 27 August 2016 17:17:17 UTC
This is a really cool feature of Azure. I already have a couple ideas on how to use this on some of my work items. Thanks for the clear example and walkthrough!
Saturday, 27 August 2016 18:24:41 UTC
Very nice info i came across. Thanks for the awesome share :)
Sunday, 28 August 2016 01:09:57 UTC
Very cool, thanks for sharing. I tried to "follow along at home" and had trouble with compiling the code as-is. Things I did to get it running:

1) Add the following:

#r "System.Drawing"

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Microsoft.Azure.WebJobs.Host;

2) Change the inputs and outputs under the "Integrate" tab to "HTTP" (default names are fine)

If MS friends are reading this - Intellisense in the browser would go a long way to help this kind of debugging.
Sunday, 28 August 2016 06:41:00 UTC
One of the PMs for Azure Functions here, answering some questions I see:

1. It uses .NET 4.6 - we hope to move to dotnet core later on.

2. This is based on WebJobs - in fact, you can find the host open source at a repo which still bares webjobs in the name. https://github.com/Azure/azure-webjobs-sdk-script

3. There is a local host for development. It's still fairly early in development, but our CLI provides a local instance - npm install -g azurefunctions

Please test in another App in the cloud though. Don't push straight to prod without testing on Azure. :)

Feel free to reach out to our team via twitter or ask questions on stack overflow, we try to stay on top of issues we see.
Chris Anderson
Sunday, 28 August 2016 11:43:41 UTC
Until when Microsoft will keep ignoring F#? Like it or not, the future is about functional and reactive programming.
Onur
Sunday, 28 August 2016 11:53:18 UTC
Oh sorry, it does support F#. Deceived by the first screenshot.
Onur
Sunday, 28 August 2016 12:04:39 UTC
"And in 2016, SkyNet became aware..."
bill
Sunday, 28 August 2016 17:47:23 UTC
Is there a way to call out from a function to another REST service? Or are functions only to sit in the middle of azure? An example would be a timed function that went and retrieved/stored results from a HTTP service.
James Corry
Monday, 29 August 2016 08:07:35 UTC
Hi,

I have been testing MS Azure & Google Cloud at the same time for two different projects.
I have been using them for high traffic websites that require on-demand resources.
But this is something new to me. Interesting article.

Thanks
Tauseef Alam
Monday, 29 August 2016 10:17:06 UTC
Scott, is there any info on what CPU my Azure Function will run on when I choose the Dynamic App Service Plan?

Thanks for a really good example of how to use Functions!

Johan
Monday, 29 August 2016 14:20:30 UTC
When I tinker with Azure Functions or Lambda, I imagine Doc in Back to the Future: "Server? Where we're going we don't need servers!"

Monday, 29 August 2016 15:24:35 UTC
Is there any built in security to control access so some malicious individual can't spam/dos your function and cost you a bunch of money?
Chad
Monday, 29 August 2016 17:02:16 UTC
Hello, I'm also with the Azure Functions team, helping answer some additional questions:

Karlo: Yes, you can add Nuget references. See more information here.

James: You can absolutely make requests from your functions and consume external services. Similar to the way Scott, is consuming the Cognitive Services API in his example.

Onur: Glad you found that F# is supported. That support is being enhanced in the next release as we've been working closely with the F# team to ensure we have great support for it.

Chad: Yes. Access control is managed at the trigger level, since different triggers offer different mechanisms (e.g. HTTP triggers support request authentication, Storage Queues and Blobs using authenticated publishers, etc.)
Fabio Cavalcante
Tuesday, 30 August 2016 07:57:46 UTC
How is this different to a really, really small web app deployed to Azure?

From the article there is still a bunch of configuration needed (just as with web app on Azure) and as someone else mentioned there is also testing to consider.

Peter
Tuesday, 30 August 2016 14:42:53 UTC
Is it possible to run a legacy win32 exe (i.e. unsafe code) via the "Batch" support?
Ian W
Tuesday, 30 August 2016 17:19:11 UTC
Thanks for explaining it clearly and quick! Still it does not look secure so far, it is like for prototyping only.
Artyom K
Tuesday, 30 August 2016 22:22:48 UTC
Scott, I was excited about playing for free with this. I immediately made 2 HipChat webhooks in it and they worked great (ported some PHP code I was running on a server somewhere else).

I thought it would be totally free given the quotas. However, I got a notification that $0.01 had already been taken from my free allocation of $200 trial just a few hours later.

I looked into the details and found it was for an auto-created storage bucket. I figured "no big deal" I'll remove that and it'll be free, since my function is totally stateless.

Now, the multi-function app is totally broken. I get:

Error:

An error occurred when trying to create a controller of type 'FunctionController'. Make sure that the controller has a parameterless public constructor.


... when I attempt to even click on the app. I'm guessing now that the functions themselves are stored in that storage bucket, but it still let me remove the bucket and now it's totally broken.

I assume I'll have to destroy the app and re-create it, but I just wanted to warn others that it's not actually free even though "Functions" has a free quota. It requires Storage.

Most disappointing, both in personal-use pricing and in it letting me totally destroy my applications (I saved most of the code in a Gist thankfully, in case I care later).

Thanks.
Tuesday, 30 August 2016 22:46:21 UTC
Hey Chris Benard,

I'm one of the PMs for Azure Functions.

You're right that we have a free grant on Dynamic Tier, but that Dynamic Tier does require Storage, so it will break when you remove it. We don't have warning on the Storage blade for removal because Storage isn't aware on what is using it, but we could probably have better warnings for you as part of our Quickstart/create process. I've created these bugs to track improving that experience:
- https://github.com/projectkudu/AzureFunctionsPortal/issues/517
- https://github.com/projectkudu/AzureFunctionsPortal/issues/516

You can use Functions in a "Free" App Service Plan, which doesn't require Storage (though we still create one by default), but it will pretty much only work with HTTP. Dynamic Tier will still require Storage, for the foreseeable future, by design. That does mean it's not totally free. I'll also follow up with our marketing/pricing material to make sure that is more clear: We have a free grant for our billing meters, but we have dependencies which aren't free.

Sorry for the confusion and some experience issues. Appreciate you reporting them to us so we can improve. :)

-Chris Anderson
Chris Anderson
Wednesday, 31 August 2016 00:48:22 UTC
I'm one of the program managers on the Azure Functions team.

Ian W: You can use some legacy Win32 code on Functions, but only if they aren't using APIs that are blocked by the underlying App Service application sandbox. For instance, GDI+ APIs can't be used. You can try uploading your .exes and see if it uses any of these.

Artyom K: Could you share more about why you don't think this would be a useful service beyond prototyping? Our goal is to enable real scenarios, but admittedly the portal tooling is not nearly as powerful as Visual Studio. :)
Donna Malayeri
Wednesday, 31 August 2016 09:19:55 UTC
This is really cool- and also worrying: every layer of 'cloud abstraction' is another opportunity to charge the customer. I wonder what kind of margins are at play here, i.e. what are you paying vs. what it would cost to execute a function on the underlying hardware.
martijn_himself
Wednesday, 31 August 2016 10:22:58 UTC
@Chris Anderson
The lack of transparency over costs the impossibility to set a spendig limit is killing your efforts to make Azure a widely used service. Individual developers avoid Azure because of this, and if there aren't enough individual developers who use your services the enterprises will not have enough resources to hire so they will not use your services.
It isn't an issue only with Functions, I followed a link from an Azure IoT article few months ago, didn't actually connect any device, yet at the end of the month I was charged $700 USD on my credit card. I was shocked. And it wasn't even possible to tell from Azure Portal which esources were generating cost and which aren't, I had to work with Azure support two days until all unwanted services, storage and others were deleted.
Besides clear visibility and detailed reports a spending limit should also be enabled:
https://feedback.azure.com/forums/170030-billing/suggestions/3238796-spending-limit-or-maximum-cost-cap-for-azure
metz2000
Wednesday, 31 August 2016 11:59:54 UTC
Hi
That's a cool example.
I followed the links and the Azure Functions Overview page states:
Choice of language - Write functions using C#, Node.js, Python, F#, PHP, batch, bash, Java, or any executable.

I use at least 4 of those languages, so I'm just asking out of curiosity:

1) I note that C++ and VB.Net aren't in the list yet. Are C# and F# considered the .NET languages of choice now?

2) It does state "Any executable" - does that mean a standalone.exe, or can you upload any supporting dlls as well?

Thanks
Diarmuid
Diarmuid
Wednesday, 31 August 2016 15:33:15 UTC
Hi,

I'm not familiar with the #r syntax in place of using. My google-fu wasn't strong enough to turn up any results. Anyone have a link that would help clarify?

Thanks!

-Nathan W.
Nathan W.
Wednesday, 31 August 2016 16:09:57 UTC
Nathan, I'm guessing that's a Nuget package directive so it will restore it. Not 100% but it makes sense how it's being used.
Wednesday, 31 August 2016 16:24:34 UTC
Thanks Chris,

Found this from a co-worker that explains it also:

https://github.com/scriptcs/scriptcs/wiki/Writing-a-script#referencing-assemblies

Nathan W.
Friday, 02 September 2016 15:39:59 UTC
When you take into consideration the fact that modern technology grows, you pretty much need to have a wireless router that might be used for the following five years. Prior to buying it, ensure that the router works with your current Personal computer.

You can browse ipaddressdefinition.com for more information
Tuesday, 06 September 2016 10:46:28 UTC
Scott, looks like your post caused something similar to the slashdot effect:

http://news.softpedia.com/news/catastrophic-ddos-attack-pummels-linode-servers-over-the-weekend-507985.shtml

Maybe the Hanselman Effect could become a thing :)
Beyers Cronje
Monday, 26 September 2016 01:15:58 UTC
Check out here, the geocode actually suggests a way to test it. it's probably something new in their documentation. cara mengobati sakit ulu hati secara alami
Amel
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.