SlideShare uma empresa Scribd logo
1 de 36
Building production 
websites with Node.js 
on the Microsoft stack 
(aka “How I Learned to Stop Worrying 
and Love edge.js”) 
Dan Polivy 
dan@cellartracker.com 
@DanPolivy
CellarTracker is the world's largest collection of wine reviews, 
tasting notes and personal stories from people who love wine. 
1.7M+ wines, 4.5M+ tasting notes (community and professional), 300,000+ registered users
Why Node.js?
Our “current” stack
Yes, that’s VBScript 
Front End IIS 
Business 
Data 
Classic ASP 
(VBScript) 
MS SQL 
Server
11 years of legacy… 
• Two web experiences built on Classic ASP/VBScript 
• Desktop and “Classic” 
• 170+ SQL tables, 25+ SQL Views 
• Existing infrastructure 
• Physical rack in Seattle datacenter 
• Virtualized on VMWare, guests running Windows Server
Mobile: not again! 
With limited resources (e.g., me), how can we modernize our 
stack to support next generation mobile web and apps 
without sacrificing our existing investments?
Node.js to the rescue? 
 We already use a lot of JavaScript for our client side 
 Lightweight development model (no compilation) 
 Async nature seems well-suited to our workload (lots of blocking DB 
queries) 
 It is (was) the new hot-ness (circa March 2013) 
? Integration with IIS 
 iisnode! 
? Integration with SQL 
 Tedious, MS NodeSQL, edge.js!
Will it blend? 
0 100 200 300 400 500 600 700 
iisnode 
Standalone 
Simulated Requests/sec 
Edge.js MS Node SQL Tedious Classic ASP 
HTTP Request returning HTML wine detail page with 5 SQL queries for data
Conclusion: Yes! 
• Async is a HUGE win for higher throughput & lower latency compared 
to serial systems like Classic ASP (and even Rails) 
• Contrary to what you might think, loading .NET in-process to talk to 
SQL yields significant performance gains vs pure JS or native (C++) 
drivers 
• Offloading heavy DB/computation lifting into .NET thread pool frees up 
Node.js’ main thread for other work 
• Marshalling data between JS and .NET has incremental cost 
• iisnode adds some (latency) overhead, but adds many useful features
iisnode 
A native IIS module that allows hosting of Node.js applications in IIS on Windows 
https://github.com/tjanczuk/iisnode
Process 
Management 
Side-by-Side Scalability 
Integrated 
Debugging 
Auto-update 
Process 
Management 
(forever) 
Side-by-Side 
(nginx) 
Scalability 
(cluster) 
Integrated 
Debugging 
(node-inspector) 
Auto-update 
(supervisor) 
Benefits
How does it work? 
Client 
• Initiates HTTP Request, e.g. ‘GET /m’ 
IIS 
• URL Rewrite rule routes request to app, e.g. ‘GET /m/server.js’ 
• iisnode handler spawns process as necessary and fwds request 
node.exe 
• Receives request via named pipe port (process.env.PORT) 
• Otherwise, works exactly the same as if it were standalone!
Why is this awesome? 
• Node.js app runs side-by-side with existing Classic ASP (or 
ASP.NET/etc) site 
• With URL rewrite module, enable IIS to serve up static content (e.g. 
client JS, CSS, images)  more performant 
• X-Forwarded-For/X-Forwarded-Proto headers can be added so you 
know the true source of the request 
• app.set('trust proxy', true); 
• Lifecycle management gracefully drains/recycles processes when JS 
changes
Integrated Debugging
edge.js and SQL 
.NET and Node.js in-process 
https://github.com/tjanczuk/edge
SQL Requirements 
• Parameterized queries 
• Input, output parameters and RETURN values 
• Call SPROCs (EXEC sp_FetchWineData) 
• Typically require multiple queries to fetch all data to render a page 
ADO.NET
Data model 
Proxy 
.NET assembly 
Bottles 
Notes 
Wines 
… 
SQL Client 
index.js 
node module 
Bottles 
Notes 
Wines 
… 
SQL Client 
edge.js 
• Separate C# assembly for data model, wrapped in JS API 
• Utilize .NET threadpool and C# async/await to parallelize queries 
• More efficient to write queries in C# and return JSON data
Example: Fetching a tasting note 
express.js route handler for /m/notes
Example: Fetching a tasting note 
cellartracker-sql.notes.getNote JS API
Example: Fetching a tasting note 
C# Notes.GetNote method
Example: Fetching a tasting note 
{ 
"Note": { 
"iNote": 3122730, 
"iWine": 1314868, 
"iUser": 60873, 
"Name": "I", 
"Favorite": 0, 
"Rating": 95, 
"TastingDate": "October 25, 2012", 
"TastingNotes": "Dark red body. Subtle perfumed nose. A beautifully elegant body 
full of plum, black cherry, and darker spices. This is a powerful wine with a long, 
lingering finish. Refined tannins, good acids and structure. This is a really nice wine 
right now, and will only get better with time!", 
"LikeIt": true, 
"AllowComments": true, 
"Votes": 1, 
"Views": 1234, 
"Defective": false, 
}, 
"Comments": [ 
{ 
"iComment": 5056, 
"iUser": 1, 
"Name": "Eric", 
"Comment": "Yum, serious wines!", 
"PostedDate": "11/13/2012 4:58pm", 
"LastEditDate": "11/13/2012 4:58pm" 
} 
], 
"Wine": { 
"iWine": 1314868, 
"Wine": "Gaja Langhe Nebbiolo Sorì San Lorenzo", 
"Vintage": "2009", 
"iProducer": 91, 
"Producer": "Gaja", 
"Locale": "Italy, Piedmont, Langhe, Langhe DOC", 
"Type": "Red", 
"Varietal": "Nebbiolo", 
"DisplayVintage": "2009", 
"FullWineName": "2009 Gaja Langhe Nebbiolo Sorì San Lorenzo", 
"SplitLocale": [ 
"Italy", 
"Piedmont", 
"Langhe", 
"Langhe DOC" 
] 
} 
} JSON Data returned from C#
General Purpose SQL Class 
• Support for SELECT, INSERT, UPDATE, DELETE, EXEC (SPROCs) 
• Parameters 
• Fully parameterized queries 
• Type (if not default) 
• Direction (in, out, inout, return) 
• Recordset Processors 
• Default: dump each row as JSON object in array 
• Return single JSON object (first row) 
• Return scalar value 
• Offset/Multiple recordsets
Error Handling 
1. Return empty JSON objects/arrays 
2. .NET Exceptions  JavaScript Error objects 
• Standard node callback signature: callback(error, result) 
• Exception is packaged up as standard Error object 
{ 
[System.AggregateException: One or more errors occurred.] 
message: 'One or more errors occurred.', 
name: 'System.AggregateException', 
InnerExceptions: 'System.Collections.ObjectModel.ReadOnlyCollection`1[[System.Exception, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]', 
Message: 'One or more errors occurred.', 
Data: 'System.Collections.ListDictionaryInternal', 
InnerException: 
{ [System.Exception: Sample exception] 
message: 'Sample exception', 
name: 'System.Exception', 
Message: 'Sample exception', 
Data: 'System.Collections.ListDictionaryInternal', 
TargetSite: 'System.Reflection.RuntimeMethodInfo', 
StackTrace: ' at Startup.<<Invoke>b__0>d__2.MoveNext() in c:UsersUser.NameSourceReposeCash2testedge2.js:line 7rn--- End of stack trace from previous location where 
exception was thrown ---rn at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)rn at 
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)rn at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()rn at 
Startup.<Invoke>d__4.MoveNext() in c:UsersUser.NameSourceReposeCash2testedge2.js:line 5', 
Source: 'cp2luegt', 
HResult: -2146233088 
}, 
HResult: -2146233088 
}
So, where are we now?
express + 
ADO.NET (C#) 
IIS 
Classic ASP 
SQL Server 
iisnode 
ADO
Apps 
• Built using Cordova framework 
• Leverage investment in mobile web 
• Backend completely powered by node.js 
• Remotely serve script to allow faster iteration 
• Add native capabilities where necessary/viable 
• Barcode scanning 
• Label image upload
Traffic 
Last 30 days: 1.6M+ page views served up by 
node.js! 
Nearly 6M page views served by Classic ASP 
on the same server. 
Mobile App Page Views/week 
Mobile Web Page Views/month
Tips, Tricks, and Lessons Learned
Encoding: UTF8 vs Windows 1252 
Our database uses Windows 1252 encoding. JavaScript uses UTF8. 
What to do? 
If only http://howfuckedismydatabase.com/ had a joke about this…
Encoding: UTF8 vs cp1252 
• Database 
• Characters with codes > 256 are HTML entity encoded, as are < and > (XSS 
prevention) 
• Classic ASP 
• Most pages set codepage to 1252, so ASP automatically does conversion/encoding 
for incoming values 
• All URLs on our desktop site are URL encoded using 1252 values 
• Node.js 
• Natively deal in UTF8, and convert when going to/from the DB 
• Edge.js/.NET handle much of it automatically, BUT we must do proper HTML entity encoding 
ourselves 
• Some manual character substitution is required (e.g. some chars have high codepoints in 
UTF8, but are below 256 in 1252) 
• Mobile URLs all use UTF8 encoding
Log file management 
• IIS logs 
• All node traffic ends up in IIS logs, so you have unified log for the server 
• BUT, you can’t tell which traffic is actually handled by node (unless you use 
paths) 
• express/node logs 
• Handled automatically by iisnode: console and stderr 
• One per node process, with a handy index.html 
• Still trying to figure out best management strategy (tips welcome!)
Git 
• Git and GitHub for Windows work great! 
• git-posh: PowerShell add-ins make life easier 
• Managing line-endings a small challenge 
• Most modules use unix endings; most of our code uses Windows 
• For now (but not ideal): set core.autocrlf to false 
• ‘git pull’ deploy 
• iisnode’s auto-refresh will automatically detect changes to JS and gracefully 
recycle processes while draining existing traffic
Other libraries 
• Testing 
• mocha 
• should 
• supertest 
• Build/automation 
• grunt 
• Front-end 
• express 
• handlebars (hbs)
Q + A
Thanks! 
Questions? Curious to learn more? Brave enough to try this yourself? Email me! 
dan@cellartracker.com

Mais conteúdo relacionado

Mais procurados

modern module development - Ken Barber 2012 Edinburgh Puppet Camp
modern module development - Ken Barber 2012 Edinburgh Puppet Campmodern module development - Ken Barber 2012 Edinburgh Puppet Camp
modern module development - Ken Barber 2012 Edinburgh Puppet Camp
Puppet
 
Node.js, toy or power tool?
Node.js, toy or power tool?Node.js, toy or power tool?
Node.js, toy or power tool?
Ovidiu Dimulescu
 
Apache Cayenne for WO Devs
Apache Cayenne for WO DevsApache Cayenne for WO Devs
Apache Cayenne for WO Devs
WO Community
 

Mais procurados (20)

Play framework
Play frameworkPlay framework
Play framework
 
12 Factor Scala
12 Factor Scala12 Factor Scala
12 Factor Scala
 
Laravel 8 export data as excel file with example
Laravel 8 export data as excel file with exampleLaravel 8 export data as excel file with example
Laravel 8 export data as excel file with example
 
Chef at WebMD
Chef at WebMDChef at WebMD
Chef at WebMD
 
Practical ERSync
Practical ERSyncPractical ERSync
Practical ERSync
 
modern module development - Ken Barber 2012 Edinburgh Puppet Camp
modern module development - Ken Barber 2012 Edinburgh Puppet Campmodern module development - Ken Barber 2012 Edinburgh Puppet Camp
modern module development - Ken Barber 2012 Edinburgh Puppet Camp
 
Os Harkins
Os HarkinsOs Harkins
Os Harkins
 
Deployment of WebObjects applications on FreeBSD
Deployment of WebObjects applications on FreeBSDDeployment of WebObjects applications on FreeBSD
Deployment of WebObjects applications on FreeBSD
 
React server side rendering performance
React server side rendering performanceReact server side rendering performance
React server side rendering performance
 
Node.js, toy or power tool?
Node.js, toy or power tool?Node.js, toy or power tool?
Node.js, toy or power tool?
 
Node.js Development with Apache NetBeans
Node.js Development with Apache NetBeansNode.js Development with Apache NetBeans
Node.js Development with Apache NetBeans
 
Bosh 2.0
Bosh 2.0Bosh 2.0
Bosh 2.0
 
RESTful Web Applications with Apache Sling
RESTful Web Applications with Apache SlingRESTful Web Applications with Apache Sling
RESTful Web Applications with Apache Sling
 
Introduction to Play Framework
Introduction to Play FrameworkIntroduction to Play Framework
Introduction to Play Framework
 
FITC - Here Be Dragons: Advanced JavaScript Debugging
FITC - Here Be Dragons: Advanced JavaScript DebuggingFITC - Here Be Dragons: Advanced JavaScript Debugging
FITC - Here Be Dragons: Advanced JavaScript Debugging
 
Into The Box 2018 Ortus Keynote
Into The Box 2018 Ortus KeynoteInto The Box 2018 Ortus Keynote
Into The Box 2018 Ortus Keynote
 
Apache Cayenne for WO Devs
Apache Cayenne for WO DevsApache Cayenne for WO Devs
Apache Cayenne for WO Devs
 
Batching and Java EE (jdk.io)
Batching and Java EE (jdk.io)Batching and Java EE (jdk.io)
Batching and Java EE (jdk.io)
 
Developing Modern Java Web Applications with Java EE 7 and AngularJS
Developing Modern Java Web Applications with Java EE 7 and AngularJSDeveloping Modern Java Web Applications with Java EE 7 and AngularJS
Developing Modern Java Web Applications with Java EE 7 and AngularJS
 
Faster Java EE Builds with Gradle
Faster Java EE Builds with GradleFaster Java EE Builds with Gradle
Faster Java EE Builds with Gradle
 

Destaque (7)

Microsoft Web Technology Stack
Microsoft Web Technology StackMicrosoft Web Technology Stack
Microsoft Web Technology Stack
 
Technology Stack KUDO.co.id
Technology Stack KUDO.co.idTechnology Stack KUDO.co.id
Technology Stack KUDO.co.id
 
Texas Association of Enterprise Architects Feb. Meeting
Texas Association of Enterprise Architects Feb. MeetingTexas Association of Enterprise Architects Feb. Meeting
Texas Association of Enterprise Architects Feb. Meeting
 
SOA in Financial Services
SOA in Financial ServicesSOA in Financial Services
SOA in Financial Services
 
DevOps-as-a-Service: Towards Automating the Automation
DevOps-as-a-Service: Towards Automating the AutomationDevOps-as-a-Service: Towards Automating the Automation
DevOps-as-a-Service: Towards Automating the Automation
 
Technology stack behind Airbnb
Technology stack behind Airbnb Technology stack behind Airbnb
Technology stack behind Airbnb
 
Microservices Technology Stack
Microservices Technology StackMicroservices Technology Stack
Microservices Technology Stack
 

Semelhante a Building production websites with Node.js on the Microsoft stack

Intro to node and mongodb 1
Intro to node and mongodb   1Intro to node and mongodb   1
Intro to node and mongodb 1
Mohammad Qureshi
 
Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)
Ran Mizrahi
 

Semelhante a Building production websites with Node.js on the Microsoft stack (20)

Intro to node and mongodb 1
Intro to node and mongodb   1Intro to node and mongodb   1
Intro to node and mongodb 1
 
Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)
 
Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)
 
Developing realtime apps with Drupal and NodeJS
Developing realtime apps with Drupal and NodeJS Developing realtime apps with Drupal and NodeJS
Developing realtime apps with Drupal and NodeJS
 
ASP.NET MVC Performance
ASP.NET MVC PerformanceASP.NET MVC Performance
ASP.NET MVC Performance
 
Wider than rails
Wider than railsWider than rails
Wider than rails
 
CouchDB for Web Applications - Erlang Factory London 2009
CouchDB for Web Applications - Erlang Factory London 2009CouchDB for Web Applications - Erlang Factory London 2009
CouchDB for Web Applications - Erlang Factory London 2009
 
Original slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talkOriginal slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talk
 
introduction to node.js
introduction to node.jsintroduction to node.js
introduction to node.js
 
Node azure
Node azureNode azure
Node azure
 
Practical Use of MongoDB for Node.js
Practical Use of MongoDB for Node.jsPractical Use of MongoDB for Node.js
Practical Use of MongoDB for Node.js
 
Scalable server component using NodeJS & ExpressJS
Scalable server component using NodeJS & ExpressJSScalable server component using NodeJS & ExpressJS
Scalable server component using NodeJS & ExpressJS
 
GlobalsDB: Its significance for Node.js Developers
GlobalsDB: Its significance for Node.js DevelopersGlobalsDB: Its significance for Node.js Developers
GlobalsDB: Its significance for Node.js Developers
 
Groovy & Grails eXchange 2012 vert.x presentation
Groovy & Grails eXchange 2012 vert.x presentationGroovy & Grails eXchange 2012 vert.x presentation
Groovy & Grails eXchange 2012 vert.x presentation
 
20120306 dublin js
20120306 dublin js20120306 dublin js
20120306 dublin js
 
Nodejs - Should Ruby Developers Care?
Nodejs - Should Ruby Developers Care?Nodejs - Should Ruby Developers Care?
Nodejs - Should Ruby Developers Care?
 
"You Don't Know NODE.JS" by Hengki Mardongan Sihombing (Urbanhire)
"You Don't Know NODE.JS" by Hengki Mardongan Sihombing (Urbanhire)"You Don't Know NODE.JS" by Hengki Mardongan Sihombing (Urbanhire)
"You Don't Know NODE.JS" by Hengki Mardongan Sihombing (Urbanhire)
 
6 tips for improving ruby performance
6 tips for improving ruby performance6 tips for improving ruby performance
6 tips for improving ruby performance
 
Nodejs and WebSockets
Nodejs and WebSocketsNodejs and WebSockets
Nodejs and WebSockets
 
Node.js: The What, The How and The When
Node.js: The What, The How and The WhenNode.js: The What, The How and The When
Node.js: The What, The How and The When
 

Último

+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
masabamasaba
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 

Último (20)

Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
 
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
 
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 

Building production websites with Node.js on the Microsoft stack

  • 1. Building production websites with Node.js on the Microsoft stack (aka “How I Learned to Stop Worrying and Love edge.js”) Dan Polivy dan@cellartracker.com @DanPolivy
  • 2. CellarTracker is the world's largest collection of wine reviews, tasting notes and personal stories from people who love wine. 1.7M+ wines, 4.5M+ tasting notes (community and professional), 300,000+ registered users
  • 5. Yes, that’s VBScript Front End IIS Business Data Classic ASP (VBScript) MS SQL Server
  • 6. 11 years of legacy… • Two web experiences built on Classic ASP/VBScript • Desktop and “Classic” • 170+ SQL tables, 25+ SQL Views • Existing infrastructure • Physical rack in Seattle datacenter • Virtualized on VMWare, guests running Windows Server
  • 7. Mobile: not again! With limited resources (e.g., me), how can we modernize our stack to support next generation mobile web and apps without sacrificing our existing investments?
  • 8. Node.js to the rescue?  We already use a lot of JavaScript for our client side  Lightweight development model (no compilation)  Async nature seems well-suited to our workload (lots of blocking DB queries)  It is (was) the new hot-ness (circa March 2013) ? Integration with IIS  iisnode! ? Integration with SQL  Tedious, MS NodeSQL, edge.js!
  • 9. Will it blend? 0 100 200 300 400 500 600 700 iisnode Standalone Simulated Requests/sec Edge.js MS Node SQL Tedious Classic ASP HTTP Request returning HTML wine detail page with 5 SQL queries for data
  • 10. Conclusion: Yes! • Async is a HUGE win for higher throughput & lower latency compared to serial systems like Classic ASP (and even Rails) • Contrary to what you might think, loading .NET in-process to talk to SQL yields significant performance gains vs pure JS or native (C++) drivers • Offloading heavy DB/computation lifting into .NET thread pool frees up Node.js’ main thread for other work • Marshalling data between JS and .NET has incremental cost • iisnode adds some (latency) overhead, but adds many useful features
  • 11. iisnode A native IIS module that allows hosting of Node.js applications in IIS on Windows https://github.com/tjanczuk/iisnode
  • 12. Process Management Side-by-Side Scalability Integrated Debugging Auto-update Process Management (forever) Side-by-Side (nginx) Scalability (cluster) Integrated Debugging (node-inspector) Auto-update (supervisor) Benefits
  • 13. How does it work? Client • Initiates HTTP Request, e.g. ‘GET /m’ IIS • URL Rewrite rule routes request to app, e.g. ‘GET /m/server.js’ • iisnode handler spawns process as necessary and fwds request node.exe • Receives request via named pipe port (process.env.PORT) • Otherwise, works exactly the same as if it were standalone!
  • 14. Why is this awesome? • Node.js app runs side-by-side with existing Classic ASP (or ASP.NET/etc) site • With URL rewrite module, enable IIS to serve up static content (e.g. client JS, CSS, images)  more performant • X-Forwarded-For/X-Forwarded-Proto headers can be added so you know the true source of the request • app.set('trust proxy', true); • Lifecycle management gracefully drains/recycles processes when JS changes
  • 16. edge.js and SQL .NET and Node.js in-process https://github.com/tjanczuk/edge
  • 17. SQL Requirements • Parameterized queries • Input, output parameters and RETURN values • Call SPROCs (EXEC sp_FetchWineData) • Typically require multiple queries to fetch all data to render a page ADO.NET
  • 18. Data model Proxy .NET assembly Bottles Notes Wines … SQL Client index.js node module Bottles Notes Wines … SQL Client edge.js • Separate C# assembly for data model, wrapped in JS API • Utilize .NET threadpool and C# async/await to parallelize queries • More efficient to write queries in C# and return JSON data
  • 19. Example: Fetching a tasting note express.js route handler for /m/notes
  • 20. Example: Fetching a tasting note cellartracker-sql.notes.getNote JS API
  • 21. Example: Fetching a tasting note C# Notes.GetNote method
  • 22. Example: Fetching a tasting note { "Note": { "iNote": 3122730, "iWine": 1314868, "iUser": 60873, "Name": "I", "Favorite": 0, "Rating": 95, "TastingDate": "October 25, 2012", "TastingNotes": "Dark red body. Subtle perfumed nose. A beautifully elegant body full of plum, black cherry, and darker spices. This is a powerful wine with a long, lingering finish. Refined tannins, good acids and structure. This is a really nice wine right now, and will only get better with time!", "LikeIt": true, "AllowComments": true, "Votes": 1, "Views": 1234, "Defective": false, }, "Comments": [ { "iComment": 5056, "iUser": 1, "Name": "Eric", "Comment": "Yum, serious wines!", "PostedDate": "11/13/2012 4:58pm", "LastEditDate": "11/13/2012 4:58pm" } ], "Wine": { "iWine": 1314868, "Wine": "Gaja Langhe Nebbiolo Sorì San Lorenzo", "Vintage": "2009", "iProducer": 91, "Producer": "Gaja", "Locale": "Italy, Piedmont, Langhe, Langhe DOC", "Type": "Red", "Varietal": "Nebbiolo", "DisplayVintage": "2009", "FullWineName": "2009 Gaja Langhe Nebbiolo Sorì San Lorenzo", "SplitLocale": [ "Italy", "Piedmont", "Langhe", "Langhe DOC" ] } } JSON Data returned from C#
  • 23. General Purpose SQL Class • Support for SELECT, INSERT, UPDATE, DELETE, EXEC (SPROCs) • Parameters • Fully parameterized queries • Type (if not default) • Direction (in, out, inout, return) • Recordset Processors • Default: dump each row as JSON object in array • Return single JSON object (first row) • Return scalar value • Offset/Multiple recordsets
  • 24. Error Handling 1. Return empty JSON objects/arrays 2. .NET Exceptions  JavaScript Error objects • Standard node callback signature: callback(error, result) • Exception is packaged up as standard Error object { [System.AggregateException: One or more errors occurred.] message: 'One or more errors occurred.', name: 'System.AggregateException', InnerExceptions: 'System.Collections.ObjectModel.ReadOnlyCollection`1[[System.Exception, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]', Message: 'One or more errors occurred.', Data: 'System.Collections.ListDictionaryInternal', InnerException: { [System.Exception: Sample exception] message: 'Sample exception', name: 'System.Exception', Message: 'Sample exception', Data: 'System.Collections.ListDictionaryInternal', TargetSite: 'System.Reflection.RuntimeMethodInfo', StackTrace: ' at Startup.<<Invoke>b__0>d__2.MoveNext() in c:UsersUser.NameSourceReposeCash2testedge2.js:line 7rn--- End of stack trace from previous location where exception was thrown ---rn at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)rn at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)rn at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()rn at Startup.<Invoke>d__4.MoveNext() in c:UsersUser.NameSourceReposeCash2testedge2.js:line 5', Source: 'cp2luegt', HResult: -2146233088 }, HResult: -2146233088 }
  • 25. So, where are we now?
  • 26. express + ADO.NET (C#) IIS Classic ASP SQL Server iisnode ADO
  • 27. Apps • Built using Cordova framework • Leverage investment in mobile web • Backend completely powered by node.js • Remotely serve script to allow faster iteration • Add native capabilities where necessary/viable • Barcode scanning • Label image upload
  • 28. Traffic Last 30 days: 1.6M+ page views served up by node.js! Nearly 6M page views served by Classic ASP on the same server. Mobile App Page Views/week Mobile Web Page Views/month
  • 29. Tips, Tricks, and Lessons Learned
  • 30. Encoding: UTF8 vs Windows 1252 Our database uses Windows 1252 encoding. JavaScript uses UTF8. What to do? If only http://howfuckedismydatabase.com/ had a joke about this…
  • 31. Encoding: UTF8 vs cp1252 • Database • Characters with codes > 256 are HTML entity encoded, as are < and > (XSS prevention) • Classic ASP • Most pages set codepage to 1252, so ASP automatically does conversion/encoding for incoming values • All URLs on our desktop site are URL encoded using 1252 values • Node.js • Natively deal in UTF8, and convert when going to/from the DB • Edge.js/.NET handle much of it automatically, BUT we must do proper HTML entity encoding ourselves • Some manual character substitution is required (e.g. some chars have high codepoints in UTF8, but are below 256 in 1252) • Mobile URLs all use UTF8 encoding
  • 32. Log file management • IIS logs • All node traffic ends up in IIS logs, so you have unified log for the server • BUT, you can’t tell which traffic is actually handled by node (unless you use paths) • express/node logs • Handled automatically by iisnode: console and stderr • One per node process, with a handy index.html • Still trying to figure out best management strategy (tips welcome!)
  • 33. Git • Git and GitHub for Windows work great! • git-posh: PowerShell add-ins make life easier • Managing line-endings a small challenge • Most modules use unix endings; most of our code uses Windows • For now (but not ideal): set core.autocrlf to false • ‘git pull’ deploy • iisnode’s auto-refresh will automatically detect changes to JS and gracefully recycle processes while draining existing traffic
  • 34. Other libraries • Testing • mocha • should • supertest • Build/automation • grunt • Front-end • express • handlebars (hbs)
  • 35. Q + A
  • 36. Thanks! Questions? Curious to learn more? Brave enough to try this yourself? Email me! dan@cellartracker.com