Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Azure F#unctions

311 views

Published on

Azure Functions + F# talk at F# Exchange 2018

  • Hey guys! Who wants to chat with me? More photos with me here 👉 http://www.bit.ly/katekoxx
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Azure F#unctions

  1. 1. AzureF#unctions @MikhailShilkov https://mikhail.io
  2. 2. • Runs on top of App Service • Web Jobs • WebJobs SDK
  3. 3. • Consumption Plan • Fixed Plan • Self-hosted Runtime (preview)
  4. 4. • £0.15 per million executions • £12 per million GB*s • Free: 400,000 GB*s / 1 million executions
  5. 5. • Timer • HTTP • Queue / Service Bus / Event Hub • Blob • Cosmos DB Change • Event Grid (and your custom events) • Integrations (Logic Apps, Stream Analytics, …)
  6. 6. Languages • C# • Javascript • F# • Java • Others, experimental
  7. 7. // run.fsx let run (myTimer: TimerInfo, log: TraceWriter) = log.Info "Welcome to F# eXchange"
  8. 8. // function.json { "bindings": [ { "type": "timerTrigger", "name": "myTimer", "schedule": "0 * * * * *" } ] } Triggered on schedule Cron expression
  9. 9. Log Code Files
  10. 10. Functions CLI
  11. 11. • Visual Studio Code + Ionide • Paket • FAKE • Expecto • Type Providers • …
  12. 12. namespace PrecompiledApp open Microsoft.AspNetCore.Mvc open Microsoft.AspNetCore.Http open Microsoft.Azure.WebJobs.Host module PrecompiledHttp = let run(req: HttpRequest, log: TraceWriter) = log.Info "HTTP is easy with Azure Functions" ContentResult(Content = "Precompiled F# FTW")
  13. 13. { "bindings": [ { "type": "httpTrigger", "methods": ["get"], "name": "req", "route": "hellohttp" } ], "scriptFile": "../bin/PrecompiledApp.dll", "entryPoint": "PrecompiledApp.PrecompiledHttp.run" } Triggered when this URL is requested What to invoke
  14. 14. [<FunctionName("YourFunctionName")>] let run( [<HttpTrigger>] req: HttpRequest, log: TraceWriter) = log.Info "F# HTTP function smooshed your request." ContentResult("function.json gets auto-generated") It’s a Function… … triggered by HTTP
  15. 15. { "generatedBy": "Microsoft.NET.Sdk.Functions.Generator-1.0.9", "configurationSource": "attributes", "bindings": [ { "type": "httpTrigger", "name": "req" } ], "scriptFile": "../bin/AttributeBasedApp.dll", "entryPoint": "AttributeBasedApp.AttributeBased.run" } Source of truth
  16. 16. [<FunctionName("Results")>] let run([<HttpTrigger(AuthorizationLevel.Anonymous, "get", "options", Route = "/products")>] req, [<DocumentDB("testdb", "testcollection", ConnectionStringSetting = "CosmosDB", SqlQuery = "SELECT top 2 * FROM c order by c._ts desc")>] documents, [<Table("SentimentTable", "DefaultPartition")>] resultsTable) = // ...
  17. 17. { "bindings": [ { "type": "queueTrigger", "name": "tweet", "queueName": "twitter" } ] }
  18. 18. { "bindings": [ { "type": "queueTrigger", "name": "tweet", "queueName": "twitter" }, { "direction": "out", "name": "$return", "type": "table", "tableName": "Sentiment" } ] } Return value goes to Table Storage
  19. 19. let run (tweet: Tweet): SentimentResult = let score = TextAnalyticsAPI.SentimentScore(tweet.Text) SentimentResult( PartitionKey = "twitter", RowKey = tweet.Id, Text = tweet.Text, Score = score)
  20. 20. { "bindings": [ { "type": "httpTrigger", "name": "req", "route": "{filename}/{name}" }, { "direction": "in", "name": "template", "type": "blob", "path": "html/{filename}.html" }, { "type": "http", "name": "$return", "direction": "out" } ] } Link
  21. 21. let run(req: HttpRequestMessage, template: string, name: string) = let html = template.Replace("%name%", name) ContentResult( Content = html, ContentType = "text/html") Comes from Blob storage
  22. 22. Function Chaining Functions
  23. 23. Workflow Orchestration
  24. 24. [<FunctionName("ChargeCreditCard")>] let ChargeCreditCard([<ActivityTrigger>] order) = //... [<FunctionName("ReserveStock")>] let ReserveStock([<ActivityTrigger>] order) = //... [<FunctionName("PlanShipment")>] let PlanShipment([<ActivityTrigger>] order) = //...
  25. 25. open FSharp.Control.Tasks [<FunctionName("OrderOrchestrator")>] let run([<OrchestrationTrigger>] context: DurableOrchestrationContext) = task { let order = context.GetInput<Order>() let! payment = context.CallActivityAsync<Payment>("ChargeCreditCard", order) let! stockItem = context.CallActivityAsync<StockItem>("ReserveStock", order) let! shipment = context.CallActivityAsync<Shipment>("PlanShipment", order) return OrderConfirmation(order, payment, stockItem, shipment) } async won’t work
  26. 26. • Stateless mindset • But instances are reused between executions
  27. 27. 0 200000 400000 600000 800000 1000000 1200000 0 1 2 3 4 5 6 7 8 9 10 11 12 13 #messagespending minutes
  28. 28. 0 100 200 300 400 500 600 700 800 900 0:00 0:10 0:20 0:30 0:40 0:50 1:00
  29. 29. 0 100 200 300 400 500 600 700 800 900 0 50 100 150 200 250 300 350 400 0:00 0:10 0:20 0:30 0:40 0:50 1:00 Requests 50th 90th 95th
  30. 30. • .NET Framework 4.7.1 • GA • All triggers supported • Full scalability • .NET Core 2.0 • Preview • WIP • Limited scalability
  31. 31. • Fast growth => Technical debt • No uniformity among Binding types • Reference version conflicts
  32. 32. • External paket.lock defined by Azure Functions team • Use it in paket.dependencies:
  33. 33. • “Developed in the open” • Scale Controller is not open
  34. 34. • “Glue”: webhooks, integration with Azure services • Prototypes • Low traffic apps • Unusual load profiles • Message/event processing
  35. 35. • Small, green-field, event-driven application • Avoid migration of existing complex projects (yet)
  36. 36. Thank You!

×