@@ -3,6 +3,7 @@ import pug from 'pug'
33import path from 'path'
44import express from 'express'
55import request from 'superagent'
6+ import promClient from 'prom-client'
67
78import l10n from '../client/l10n'
89import render from '../client/run-server'
@@ -17,9 +18,35 @@ const rpath = p => path.join(__dirname, p)
1718
1819const indexView = rpath ( '../../client/index.pug' )
1920
21+ const register = new promClient . Registry ( )
22+
23+ const activeRenders = new promClient . Gauge ( {
24+ name : 'prerender_active_renders' ,
25+ help : 'Number of active renders'
26+ } )
27+
28+ const totalRenders = new promClient . Counter ( {
29+ name : 'prerender_total_renders' ,
30+ help : 'Total number of renders completed'
31+ } )
32+
33+ const renderDuration = new promClient . Histogram ( {
34+ name : 'prerender_render_duration_seconds' ,
35+ help : 'Duration of renders in seconds'
36+ } )
37+
38+ register . registerMetric ( activeRenders )
39+ register . registerMetric ( totalRenders )
40+ register . registerMetric ( renderDuration )
41+
2042const app = express ( )
2143app . engine ( 'pug' , pug . __express )
2244
45+ app . get ( '/metrics' , ( req , res ) => {
46+ res . set ( 'Content-Type' , register . contentType )
47+ res . end ( register . metrics ( ) )
48+ } )
49+
2350if ( app . settings . env == 'development' )
2451 app . use ( require ( 'morgan' ) ( 'dev' ) )
2552
@@ -37,25 +64,50 @@ app.use((req, res, next) => {
3764 if ( ! langs . includes ( lang ) ) lang = 'en'
3865 if ( req . query . lang && req . cookies . lang !== lang ) res . cookie ( 'lang' , lang )
3966
40- render ( req . _parsedUrl . pathname , req . _parsedUrl . query || '' , req . body , { theme, lang, isHead : req . method === 'HEAD' } , ( err , resp ) => {
41- if ( err ) return next ( err )
42- if ( resp . redirect ) return res . redirect ( 301 , baseHref + resp . redirect . substr ( 1 ) )
43- if ( resp . errorCode ) {
44- console . error ( `Failed with code ${ resp . errorCode } :` , resp )
45- return res . sendStatus ( resp . errorCode )
67+ if ( typeof process . send === 'function' ) {
68+ const requestId = Math . random ( ) . toString ( 36 )
69+ process . send ( { type : 'startRender' , requestId } )
70+ const handler = ( msg ) => {
71+ if ( msg . requestId === requestId ) {
72+ process . removeListener ( 'message' , handler )
73+ if ( msg . type === 'renderAllowed' ) {
74+ doRender ( )
75+ } else if ( msg . type === 'renderDenied' ) {
76+ res . status ( 503 ) . send ( 'Server overloaded' )
77+ }
78+ }
4679 }
80+ process . on ( 'message' , handler )
81+ } else {
82+ doRender ( )
83+ }
4784
48- res . status ( resp . status || 200 )
49- res . render ( indexView , {
50- prerender_title : resp . title
51- , prerender_html : resp . html
52- , canon_url : canonBase ? canonBase + req . url : null
53- , noscript : true
54- , theme
55- , t : l10n [ lang ]
56- } )
57- } )
85+ function doRender ( ) {
86+ activeRenders . inc ( )
87+ const end = renderDuration . startTimer ( )
88+ render ( req . _parsedUrl . pathname , req . _parsedUrl . query || '' , req . body , { theme, lang, isHead : req . method === 'HEAD' } , ( err , resp ) => {
89+ if ( typeof process . send === 'function' ) process . send ( { type : 'endRender' } )
90+ activeRenders . dec ( )
91+ end ( )
92+ totalRenders . inc ( )
93+ if ( err ) return next ( err )
94+ if ( resp . redirect ) return res . redirect ( 301 , baseHref + resp . redirect . substr ( 1 ) )
95+ if ( resp . errorCode ) {
96+ console . error ( `Failed with code ${ resp . errorCode } :` , resp )
97+ return res . sendStatus ( resp . errorCode )
98+ }
5899
100+ res . status ( resp . status || 200 )
101+ res . render ( indexView , {
102+ prerender_title : resp . title
103+ , prerender_html : resp . html
104+ , canon_url : canonBase ? canonBase + req . url : null
105+ , noscript : true
106+ , theme
107+ , t : l10n [ lang ]
108+ } )
109+ } )
110+ }
59111} )
60112
61113// Cleanup socket file from previous executions
0 commit comments