@@ -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,37 @@ 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+
42+ let requestCounter = 0
43+
2044const app = express ( )
2145app . engine ( 'pug' , pug . __express )
2246
47+ app . get ( '/metrics' , async ( req , res ) => {
48+ res . set ( 'Content-Type' , register . contentType )
49+ res . end ( await register . metrics ( ) )
50+ } )
51+
2352if ( app . settings . env == 'development' )
2453 app . use ( require ( 'morgan' ) ( 'dev' ) )
2554
@@ -37,25 +66,54 @@ app.use((req, res, next) => {
3766 if ( ! langs . includes ( lang ) ) lang = 'en'
3867 if ( req . query . lang && req . cookies . lang !== lang ) res . cookie ( 'lang' , lang )
3968
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 )
69+ if ( typeof process . send === 'function' ) {
70+ const requestId = ++ requestCounter
71+ process . send ( { type : 'startRender' , requestId } )
72+ const handler = ( msg ) => {
73+ if ( msg . requestId === requestId ) {
74+ process . removeListener ( 'message' , handler )
75+ if ( msg . type === 'renderAllowed' ) {
76+ doRender ( )
77+ } else if ( msg . type === 'renderDenied' ) {
78+ res . status ( 503 ) . send ( 'Server overloaded' )
79+ }
80+ }
4681 }
82+ process . on ( 'message' , handler )
83+ } else {
84+ doRender ( )
85+ }
4786
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- } )
87+ function doRender ( ) {
88+ activeRenders . inc ( )
89+ const end = renderDuration . startTimer ( )
90+ let metricsUpdated = false
91+ render ( req . _parsedUrl . pathname , req . _parsedUrl . query || '' , req . body , { theme, lang, isHead : req . method === 'HEAD' } , ( err , resp ) => {
92+ if ( ! metricsUpdated ) {
93+ metricsUpdated = true
94+ if ( typeof process . send === 'function' ) process . send ( { type : 'endRender' } )
95+ activeRenders . dec ( )
96+ end ( )
97+ totalRenders . inc ( )
98+ }
99+ if ( err ) return next ( err )
100+ if ( resp . redirect ) return res . redirect ( 301 , baseHref + resp . redirect . substr ( 1 ) )
101+ if ( resp . errorCode ) {
102+ console . error ( `Failed with code ${ resp . errorCode } :` , resp )
103+ return res . sendStatus ( resp . errorCode )
104+ }
58105
106+ res . status ( resp . status || 200 )
107+ res . render ( indexView , {
108+ prerender_title : resp . title
109+ , prerender_html : resp . html
110+ , canon_url : canonBase ? canonBase + req . url : null
111+ , noscript : true
112+ , theme
113+ , t : l10n [ lang ]
114+ } )
115+ } )
116+ }
59117} )
60118
61119// Cleanup socket file from previous executions
0 commit comments