REST API Connected Apps Windows Store iOS Android Windows Phone 8 iOS Android HTML 5/JS.

Post on 18-Jan-2016

240 views 0 download

Tags:

Transcript of REST API Connected Apps Windows Store iOS Android Windows Phone 8 iOS Android HTML 5/JS.

Mobile Services: Going Live and Beyond

Kirill Gavrylyuk, Lead Program ManagerPaul Batum, Program Manager3-511

RES

T A

PI

Data

Notifications

Auth

Server Logic

Scale

Scheduler

Diagnostics &Logging

Connected Apps

Windows StoreiOS

Android

Windows Phone 8iOS

AndroidHTML 5/JS

Dev&Test

Tune Perf

Go LiveMonitor

Version

Event Buddy

DEMO

Source Control and Deployment

Local git repository

Mobile Services(git repository)

Team Foundation Service(git repository)

Automation

DEMO

Using ZumockScripts Unit Testing

DEMO

Node.js Tools

.NET Node.js

NuGet <---->Node Package Manager (NPM)

NUnit / MS test / etc <----> Mocha

Keep scripts in source control (TFS) Use Git to deploy server scriptsAutomate using Azure CLITest scripts using mock frameworks

Dev & Test Summary

Dev&Test

Tune Perf

Go LiveMonitor

Version

Use SQL Database forrelational datarich query, sorting, filtering, multiple indexes

Use Table forkey-value pair tuples (e.g. game state)simple queries, basic or no filtering

SQL Database vs Table

Table Storage with Custom APIs

exports.get = function (request, response) {

var azure = require('azure');

var tableService = azure.createTableService(‘session', '<your storage key>');

var query = azure.TableQuery.select().from(‘session').where(‘eventId eq ?‘, eventId);

tableService.queryEntities(query, function (error, todoitems) {

if (!error) {

response.send(200, todoitems);

} else { /* … */}

});

};

Working with images / blobs

Blob Storage

Mobile Service

1

2

3

4 1. Request a blob url2. Request a SAS token3. Send back a blob url4. Post a blob

Blob Storage SAS

function insert(item, user, request) {

var azure = require('azure');

var blobService = azure.createBlobService('<account-name>', 'account-key>');

blobService.createContainerIfNotExists(item.containerName,

accessLevel, function (error) {

if (error) { return errorHandler(error); }

var sharedAccessPolicy = {Permissions : /* ... */, Expiry : /* ... */};

var sasQueryUrl = blobService.generateSharedAccessSignature(item.containerName,

item.resourceName, sharedAccessPolicy);

item.imageUri = sasQueryUrl.baseUrl + sasQueryUrl.path;

request.execute();

});

}

DO NOT use compute intense scripts

function insert(item, user, request) {

//...

images.forEach(function (image) {

var png = easyimg.jpg2png(image, quality:10};

//...

}

USE SQL where appropriate

postTable.where({id : commment.postId}).read( { success : pushToUsers });

//…

function pushToUsers(users) {

users.forEach(function (userId) {

channelTable.where(userId : userId).read({

success: function(channels) {

channels.forEach(function(channel) {

push.wns.sendToastText04(channel.uri, {text1: item.text } );

});

}

});

});

}

JOINS BETTER IN SQL

USE SQL where appropriate

var sql = "SELECT channel FROM devices " +

"INNER JOIN posts ON devices.userId = posts.userId " +

"WHERE posts.id = ?";

mssql.query(sql, [comment.postId], {

success: function(channels) {

channels.forEach(function(channel) {

push.wns.sendToastText04(channel.uri, {text1: item.text } );

});

}

AVOID doing 1000s requests in parallelvar sql = "SELECT channel FROM devices " +

"INNER JOIN users ON "; // TO DO: query users in SF

mssql.query(sql, [geofences.SF], {

success: function(channels) {

channels.forEach(function(channel) {

push.wns.sendToastText04(channel.uri,

{text1: “New Coffee” } );

});

}

• Use Notification Hubs

• Split the work into batches and process in the background

AVOID client side JOINs

IEnumerable<Session> sessions;

Events = await App.MobileService.GetTable<Event>()

.Where(e => e.Start > DateTime.Now)

.ToEnumerableAsync();

foreach (var e in Events)

{

sessions = await App.MobileService

.GetTable<Session>()

.ToEnumerableAsync();

/*....*/

}

IEnumerable<Session> sessions;

Events = await App.MobileService

.GetTable<Session>()

.Where(e => s.Start > DateTime.Now)

.ToEnumerableAsync();

/*....*/

//JOIN in server scripts:

var sql = "SELECT * FROM sessions " +

"INNER JOIN events ON events.date > ?";

mssql.query(sql, [startDate], {

/*....*/

}

LOTS O

F API

CALLS

Choose the right data storeUse Blob Storage for binary blobsAVOID compute-intense scripts• USE MSSQL when SQL is best• AVOID 1000s requests in parallel

USE client-server communication efficiently• DO NOT join tables on the client• DO batch updates as appropriate

Perf tuning tips

Dev&Test

Tune Perf

Go LiveMonitor

Version

Mobile Services Tierspricing & licensing $ service level

agreements

General Availability99.9%

Free Standard Premium

Price FreeUp to 10 services,Up to 100 Active

Devices**

$25 USD/mo(per unit**)

$199 USD/mo(per unit**)

API Calls 500K (per subscription)

1.5M(per unit)

15M(per unit)

Scale N/A Up to 6 Standard units

Up to 10 Enterprise units

Min Burstper instance

10 RPS 100 RPS

SQL Database (required)

20MB Included, Standard rates apply

for more capacity

20MB Included, Standard rates apply

for more capacity

20MB Included, Standard rates apply

for more capacity

*prorated daily

**Active devices refers to the number of unique devices that have both obtained your Mobile Services powered app from a public app store and have made at least one call to your mobile service over the past 30 days.

Choose the right TierDisable Dynamic SchemaEnsure Auth is ON, use SSLLock permissionsSetup dev / test environmentsThink versioning

Go Live!

Dev&Test

Tune Perf

Go LiveMonitor

Version

Creating & Configuring Alerts

DEMO

Monitor your app with New Relic

DEMO

Availability monitoring / alertsBetter with partners: New Relic

Monitoring & Troubleshooting

Dev&Test

Tune Perf

Go LiveMonitor

Version

Add version to your Mobile Services clientpublic class VersioningHandler : DelegatingHandler{

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken

cancellationToken) {

request.RequestUri = new Uri(request.RequestUri.AbsoluteUri.ToString() + “?version=2.0");

return base.SendAsync(request, cancellationToken); }}

public static MobileServiceClient MobileService = new MobileServiceClient(

"https://eventbuddykg.azure-mobile.net/",

"lLsNsvgOmQBfUGOHgKkIgnFwblJpla63",

new VersioningHandler()

);

Add version to your scripts

function insert(item, user, request) {

if (request.parameters.version < 2.0) {

session.room = 'Not entered';

}

request.execute({

success: function () {

if (request.parameters.version < 2.0) {

delete session.room;

}

request.respond();

}

});

}

DEMO

Prepare for breaking changes

Include client version in requestsHandle version differences in scriptsPlan your upgrade strategy

Versioning Considerations

Use source control for server scripts Automate using CLI & PowerShell Unit test using mock frameworks Be efficient about network and server

scripts Pick the appropriate tier Think about versioning upfront

Summary

Mobile Services at BuildMobile Services – Soup to NutsJosh Twist – Thursday 2pm

Protips for Mobile ServicesChris Risner – Thursday 5pm

Cross-Platform w/ Mobile ServicesChris Risner – Thursday 4pm

Connected Win Phone AppsYavor Georgiev – Friday 9am

Going Live and BeyondKirill and Paul – Friday 10:30am

Delivering Push Notifications to MillionsElio Demaggio – Friday 12pm

Who’s that user?Dinesh Kulkarni – Friday 2pm

Developing Windows AppsNick Harris – Friday 2pm

ResourcesGet started with Mobile Services:http://www.windowsazure.com/en-us/develop/mobile/

Get started with the Azure CLI:http://www.windowsazure.com/en-us/develop/nodejs/how-to-guides/command-line-tools/

Copying a SQL Azure Database:http://msdn.microsoft.com/en-us/library/windowsazure/ff951631.aspx

Setting up New Relic:http://blog.newrelic.com/

Evaluate this session

Scan this QR code to evaluate this session and be automatically entered in a drawing to win a prize!

© 2013 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.