[MediaWiki-commits] [Gerrit] mediawiki...chromium-render[master]: Abort render on connection close

2017-11-28 Thread Pmiazga (Code Review)
Pmiazga has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/392932 )

Change subject: Abort render on connection close
..


Abort render on connection close

When the client closes the connection:
- if the task is still waiting in the queue, remove it;
- if the task has already started, abort render.

Bug: T180604
Change-Id: I47f6847948ed8903c54fdaaf4fcb5ff021d46c76
---
M lib/queue.js
M package.json
M routes/html2pdf-v1.js
M test/lib/queue.js
4 files changed, 129 insertions(+), 15 deletions(-)

Approvals:
  Pmiazga: Verified; Looks good to me, approved
  Jdlrobson: Looks good to me, but someone else must approve



diff --git a/lib/queue.js b/lib/queue.js
index ff437ac..525f75b 100644
--- a/lib/queue.js
+++ b/lib/queue.js
@@ -2,7 +2,6 @@
 
 const asyncQueue = require('async/queue');
 const asyncTimeout = require('async/timeout');
-const uuid = require('cassandra-uuid');
 
 // Errors used as the first argument of the callback passed to the queue
 const callbackErrors = {
@@ -79,14 +78,13 @@
 const queue = this._queueObject;
 const timeout = this._options.queueTimeout;
 
-data._id = `${uuid.TimeUuid.now().toString()}|${data.uri}`;
 data._timeoutID = setTimeout(() => {
 queue.remove((worker) => {
-if (worker.data._id === data._id) {
+if (worker.data.id === data.id) {
 logger.log(
 'warn/queue',
 `Queue is still busy after waiting ` +
-`for ${timeout} secs. Data ID: ${data._id}.`
+`for ${timeout} secs. Data ID: ${data.id}.`
 );
 callback(callbackErrors.queueBusy, null);
 return true;
@@ -123,11 +121,12 @@
 callback(callbackErrors.queueFull, null);
 return;
 }
+
 // make sure to cancel the task if it doesn't start within a timeframe
 this._setCancelTaskTimeout(data, callback);
 const queueSize = this._countJobsInQueue();
 this._logger.log(
-'debug/queue', `Job ${data._id} added to the queue. Jobs waiting: 
${queueSize}`
+'debug/queue', `Job ${data.id} added to the queue. Jobs waiting: 
${queueSize}`
 );
 this._queueObject.push(data, callback);
 }
@@ -143,21 +142,20 @@
  */
 _worker(data, callback) {
 this._clearCancelTaskTimeout(data);
-this._logger.log('info/queue', `Started rendering ${data._id}`);
+this._logger.log('info/queue', `Started rendering ${data.id}`);
 
 const timeout = this._options.executionTimeout;
 const timedRender = asyncTimeout(this._render.bind(this),
  timeout * 1000);
-const renderer = data._renderer;
 timedRender(data, (error, pdf) => {
 // error returned by async timeout
 if (error && error.code === 'ETIMEDOUT') {
 this._logger.log(
 'error/render',
 `Aborting. Render hasn't finished within ${timeout} ` +
-`seconds. Data ID: ${data._id}.`
+`seconds. Data ID: ${data.id}.`
 );
-renderer.abortRender();
+data.renderer.abortRender();
 callback(callbackErrors.renderTimeout, null);
 } else {
 callback(error, pdf);
@@ -171,23 +169,53 @@
  * @param {Function} callback called on render success/failure
  */
 _render(data, callback) {
-data._renderer
+data.renderer
 .articleToPdf(data.uri, data.format, this._puppeteerOptions,
   this._pdfOptions)
 .then((pdf) => {
 this._logger.log(
-'debug/queue', `Job ${data._id} rendered successfully`
+'debug/queue', `Job ${data.id} rendered successfully`
 );
 callback(null, pdf);
 })
 .catch((error) => {
 this._logger.log('error/render', {
-msg: `Cannot convert page ${data.uri} to PDF. Error: 
${error.toString()}`,
+msg: `Data ID: ${data.id} to PDF. ${error.toString()}`,
 error
 });
 callback(callbackErrors.renderFailed, null);
 });
 }
+
+/**
+ * Abort task identified by `id`
+ * @param {string} id ID initially passed as part of data
+ * @param {Renderer} renderer instance of Renderer
+ */
+abort(id, renderer) {
+let taskStarted = true;
+
+// has the task started already?
+this._queueObject.remove((worker) => {
+if (worker.data.id === id) {
+this._logger.log(
+'debug/queue',
+ 

[MediaWiki-commits] [Gerrit] mediawiki...chromium-render[master]: Abort render on connection close

2017-11-22 Thread Bmansurov (Code Review)
Bmansurov has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/392932 )

Change subject: Abort render on connection close
..

Abort render on connection close

When the client closes the connection:
- if the task is still waiting in the queue, remove it;
- if the task has already started, abort render.

Bug: T180604
Change-Id: I47f6847948ed8903c54fdaaf4fcb5ff021d46c76
---
M lib/queue.js
M package.json
M routes/html2pdf-v1.js
M test/lib/queue.js
4 files changed, 134 insertions(+), 20 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/services/chromium-render 
refs/changes/32/392932/1

diff --git a/lib/queue.js b/lib/queue.js
index 3330f79..360db88 100644
--- a/lib/queue.js
+++ b/lib/queue.js
@@ -2,8 +2,6 @@
 
 const asyncQueue = require('async/queue');
 const asyncTimeout = require('async/timeout');
-const Renderer = require('./renderer');
-const uuid = require('cassandra-uuid');
 
 // Errors used as the first argument of the callback passed to the queue
 const callbackErrors = {
@@ -38,15 +36,16 @@
  * @param {Object} puppeteerOptions options used to in starting puppeteer
  * @param {Object} pdfOptions pdf options passed to Chromium
  * @param {Object} logger app logger
+ * @param {Renderer} renderer an instance of PDF renderer
  */
-constructor(queueOptions, puppeteerOptions, pdfOptions, logger) {
+constructor(queueOptions, puppeteerOptions, pdfOptions, logger, renderer) {
 this._queueObject = asyncQueue(this._worker.bind(this),
queueOptions.concurrency);
 this._puppeteerOptions = puppeteerOptions;
 this._pdfOptions = pdfOptions;
 this._options = queueOptions;
 this._logger = logger;
-this._renderer = new Renderer();
+this._renderer = renderer;
 }
 
 /**
@@ -81,14 +80,13 @@
 const queue = this._queueObject;
 const timeout = this._options.queueTimeout;
 
-data._id = `${uuid.TimeUuid.now().toString()}|${data.uri}`;
 data._timeoutID = setTimeout(() => {
 queue.remove((worker) => {
-if (worker.data._id === data._id) {
+if (worker.data.id === data.id) {
 logger.log(
 'warn/queue',
 `Queue is still busy after waiting ` +
-`for ${timeout} secs. Data ID: ${data._id}.`
+`for ${timeout} secs. Data ID: ${data.id}.`
 );
 callback(callbackErrors.queueBusy, null);
 return true;
@@ -129,7 +127,7 @@
 this._setCancelTaskTimeout(data, callback);
 const queueSize = this._countJobsInQueue();
 this._logger.log(
-'debug/queue', `Job ${data._id} added to the queue. Jobs waiting: 
${queueSize}`
+'debug/queue', `Job ${data.id} added to the queue. Jobs waiting: 
${queueSize}`
 );
 this._queueObject.push(data, callback);
 }
@@ -145,7 +143,7 @@
  */
 _worker(data, callback) {
 this._clearCancelTaskTimeout(data);
-this._logger.log('info/queue', `Started rendering ${data._id}`);
+this._logger.log('info/queue', `Started rendering ${data.id}`);
 
 const timeout = this._options.executionTimeout;
 const timedRender = asyncTimeout(this._render.bind(this),
@@ -157,7 +155,7 @@
 this._logger.log(
 'error/render',
 `Aborting. Render hasn't finished within ${timeout} ` +
-`seconds. Data ID: ${data._id}.`
+`seconds. Data ID: ${data.id}.`
 );
 renderer.abortRender();
 callback(callbackErrors.renderTimeout, null);
@@ -178,18 +176,47 @@
   this._pdfOptions)
 .then((pdf) => {
 this._logger.log(
-'debug/queue', `Job ${data._id} rendered successfully`
+'debug/queue', `Job ${data.id} rendered successfully`
 );
 callback(null, pdf);
 })
 .catch((error) => {
 this._logger.log('error/render', {
-msg: `Cannot convert page ${data.uri} to PDF. Error: 
${error.toString()}`,
+msg: `Data ID: ${data.id} to PDF. ${error.toString()}`,
 error
 });
 callback(callbackErrors.renderFailed, null);
 });
 }
+
+/**
+ * Abort task identified by `id`
+ * @param {string} id ID initially passed as part of data
+ */
+abort(id) {
+let taskStarted = true;
+
+// has the task started already?
+this._queueObject.remove((worker) => {
+if (worker.data.id === id) {
+this._logger.log(
+