Aborted upload causes Sails js/Skipper to crash - file-upload

Ref: https://github.com/balderdashy/skipper/issues/49
Adapter: skipper-gridfs
Basic controller code:
req.file('fileTest')
.upload({
// You can apply a file upload limit (in bytes)
maxBytes: maxUpload,
adapter: require('skipper-gridfs'),
uri: bucketConnect,
saveAs : function (__newFileStream,cb) {
cb(null, __newFileStream.filename);
}
}, function whenDone(err, uploadedFiles) {
if (err) {
var error = { "status": 500, "error" : err };
return res.serverError(error);
}else {
I have a jQuery-File-Upload client ( https://blueimp.github.io/jQuery-File-Upload/ ) impementing the "cancel" procedure by using jqXHR abort described here (https://github.com/blueimp/jQuery-File-Upload/wiki/API ):
$('button.cancel').click(function (e) {
jqXHR.abort();
});
After the client aborts, the server crashes with the following message:
events.js:72
throw er; // Unhandled 'error' event
^
Error: Request aborted
at IncomingMessage.onReqAborted (.../node_modules/sails/node_modules/skipper/node_modules/multiparty/index.js:175:17)
at IncomingMessage.EventEmitter.emit (events.js:92:17)
at abortIncoming (http.js:1911:11)
at Socket.serverSocketCloseListener (http.js:1923:5)
at Socket.EventEmitter.emit (events.js:117:20)
at TCP.close (net.js:466:12)
I've used try/catch but it didn't work, the server crashes anyway.
I am not sure if this is a Skipper issue or a Multiparty issue -- my knowledge stops here ( https://github.com/andrewrk/node-multiparty/blob/master/index.js ):
function onReqAborted() {
waitend = false;
self.emit('aborted');
handleError(new Error("Request aborted"));
}
function onReqEnd() {
waitend = false;
}
function handleError(err) {
var first = !self.error;
if (first) {
self.error = err;
req.removeListener('aborted', onReqAborted);
req.removeListener('end', onReqEnd);
if (self.destStream) {
self.destStream.emit('error', err);
}
}
cleanupOpenFiles(self);
if (first) {
self.emit('error', err);
}
}
At first I thought this was the way the jqXHR request was aborted, but it seems to be a generic Skipper issue on aborted uploads, since the simple act of closing the tab during an upload will crash the server (different message):
_stream_writable.js:233
cb(er);
^
TypeError: object is not a function
at onwriteError (_stream_writable.js:233:5)
at onwrite (_stream_writable.js:253:5)
at WritableState.onwrite (_stream_writable.js:97:5)
at Writable.<anonymous> (.../node_modules/skipper-gridfs/index.js:179:25)
at Writable.g (events.js:180:16)
at Writable.EventEmitter.emit (events.js:117:20)
at PassThrough.<anonymous> (.../node_modules/skipper-gridfs/index.js:194:36)
at PassThrough.g (events.js:180:16)
at PassThrough.EventEmitter.emit (events.js:117:20)
at .../node_modules/sails/node_modules/skipper/standalone/Upstream/prototype.fatalIncomingError.js:55:17
I have tried aborting the upload by closing the tab while using a simple upload controller (not Skipper) and there is no crash:
var uploadFile = req.file('fileTest');
console.log(uploadFile);
uploadFile.upload(function onUploadComplete (err, files) { // Files will be uploaded to .tmp/uploads
if (err) return res.serverError(err); // IF ERROR Return and send 500 error with error
console.log(files);
res.json({status:200,file:files});
});
So, did anybody see this happening and is there any workaround?

This issue has been solved in skipper#0.5.4 and skipper-disk#0.5.4
Ref.: https://github.com/balderdashy/skipper/issues/49

Also there is an Issue in skipper-gridfs#0.5.3
Link: https://github.com/willhuang85/skipper-gridfs/issues/20

Related

RabbitMQ StompJs recieving just one Message

I'm trying to recieve a Message from the RabbitMq-Que with the Stomp-plugin. This works fine but the Problem is that I get every Message from the Queue. So if the Queue has 13 Messages, I get 13. The Key is that I just want to get 1 Message and after sending Ack or Nack the next one. Do somebody got any Idea how to get only one Message? Thanks for Help.
Here the code I got:
GetMessage()
{
this.GetRabbitMqClient().then((client)=>
{
var headers ={ack:'client', 'x-max-priority': '10'};
var subscription = client.subscribe("/queue/TestQue",this.messageCallback,headers);
});
}
private messageCallback = function(Message :IMessage)
{
console.log(Message.body);
setTimeout(()=> {Message.ack();},100000000000000);
}
private GetRabbitMqClient( ):Promise<Client> {
var promise = new Promise<Client>((resolve,reject)=>{
var client = new Client(
{
brokerURL: "ws://localhost:15674/ws",
connectHeaders:
{
login: "guest",
passcode: "guest"
},
// debug: function (str) {
// console.log(str);
// },
reconnectDelay: 5000,
heartbeatIncoming: 4000,
heartbeatOutgoing: 4000
});
client.onConnect = function (frame) {
resolve(client);
};
client.onStompError = function (frame) {
// Will be invoked in case of error encountered at Broker
// Bad login/passcode typically will cause an error
// Complaint brokers will set `message` header with a brief message. Body may contain details.
// Compliant brokers will terminate the connection after any error
reject(frame);
console.log('Broker reported error: ' + frame.headers['message']);
console.log('Additional details: ' + frame.body);
};
client.activate();
});
return promise;
}
I found the solution:
you just need to set in the headers the attribute:
'prefetch-count':'1'

How to getQueryResults() of 1 job after createQueryJob() successfully in Google BigQuery?

I'm using google cloud big query service with nodejs client version 1.0x . I created a job successfully by function createQueryJob(). After that, I used an event listen when a callback create job response with getQueryResults() such as:
const options = {
query: sqlQuery,
useLegacySql: true,
dryRun: true
};
// this.bigquery is an constructor.
// this.bigquery = new BigQuery({
// projectId: this.projectId,
// keyFilename: this.keyFile,
// });
this.bigquery.createQueryJob(options, function (err, job) {
if (!err) {
// job id such as 731bf23b-5044-4842-894b-4d9f77485d9b
function manualPaginationCallback(err, rows, nextQuery, apiResponse) {
if (nextQuery) {
job.getQueryResults(nextQuery, manualPaginationCallback);
} else {
return Promise.resolve(rows);
}
}
return job.getQueryResults({
maxResults: 100000,
autoPaginate: false,
// timeoutMs : 60000
}, manualPaginationCallback);
}
});
But It throw an error
{"error":{"code":404,"message":"Not found: Job
[myProjectId]:731bf23b-5044-4842-894b-4d9f77485d9b","errors":[{"message":"Not
found: Job
[myProjectId]:731bf23b-5044-4842-894b-4d9f77485d9b","domain":"global","reason":"notFound"}],"status":"NOT_FOUND"}}
refrence
https://cloud.google.com/nodejs/docs/reference/bigquery/1.0.x/BigQuery#createQueryJob
https://cloud.google.com/nodejs/docs/reference/bigquery/1.0.x/Job#getQueryResults
What wrong's with me? Any help. Thank you!
You're setting the dryrun option in your request, which only validates the job but doesn't actually run the query. Dryrun jobs don't persist, which is why you get not found on the subsequent request.

How to recover a error message from oData response [SAPUI5]

I had this issue and i searched a lot how to fix it, but i can't find any solution at the moment...
well, the issue is the next error message, i can write the error but i need a specific entry of this batch.
the code showed on the message box:
{
"message": "HTTP request failed",
"headers": {
"Content-Type": "application/xml;charset=utf-8",
"Content-Length": "1333",
"DataServiceVersion": "1.0"
},
"statusCode": "400",
"statusText": "Bad Request",
"responseText": "<?xml version=\"1.0\" encoding=\"utf-8\"?><error xmlns=\"http://schemas .microsoft.com/ado/2007/08/dataservices/metadata\"><code>SY/530</code><message xml:lang=\"es\">No posee permisos para el Centro seleccionado</message><innererror><application><component_id/><service_namespace>/SAP/</service_namespace><service_id>ZQMGW_LECTURATANQUE_SRV</service_id><service_version>0001</service_version></application><transactionid>9488BBDEFA9E11E685950000705EE2FB</transactionid><timestamp>20170224144147.5230000</timestamp><Error_Resolution><SAP_Transaction>Run transaction /IWFND/ERROR_LOG on SAP Gateway hub system and search for entries with the timestamp above for more details</SAP_Transaction><SAP_Note>See SAP Note 1797736 for error analysis (https: //service. sap .com/sap/support/notes/1797736)</SAP_Note><Batch_SAP_Note>See SAP Note 1869434 for details about working with $batch (https: //service. sap. com/sap/support/notes/1869434)</Batch_SAP_Note></Error_Resolution><errordetails><errordetail><code/><message>No posee permisos para el Centro seleccionado</message><propertyref/><severity>error</severity><target/></errordetail><errordetail><code>/IWBEP/CX_SD_GEN_DPC_BUSINS</code><message>No posee permisos para el Centro seleccionado</message><propertyref/><severity>error</severity><target/></errordetail></errordetails></innererror></error>"
}
i need to recover the message tag only, but i don't know how....
the code what i'm using is the native error handling for Sapui5 Fiori Apps:
constructor: function(oComponent) {
this._oResourceBundle = oComponent.getModel("i18n").getResourceBundle();
this._oComponent = oComponent;
this._oModel = oComponent.getModel();
this._bMessageOpen = false;
this._sErrorText = this._oResourceBundle.getText("errorText");
this._oModel.attachMetadataFailed(function(oEvent) {
var oParams = oEvent.getParameters();
this._showServiceError(oParams.response);
}, this);
this._oModel.attachRequestFailed(function(oEvent) {
var oParams = oEvent.getParameters("message");
// An entity that was not found in the service is also throwing a 404 error in oData.
// We already cover this case with a notFound target so we skip it here.
// A request that cannot be sent to the server is a technical error that we have to handle though
if (oParams.response.statusCode !== "404" || (oParams.response.statusCode === 404 && oParams.response.responseText.indexOf(
"Cannot POST") === 0)) {
this._showServiceError(oParams.response);
}
}, this);
},
/**
* Shows a {#link sap.m.MessageBox} when a service call has failed.
* Only the first error message will be display.
* #param {string} sDetails a technical error to be displayed on request
* #private
*/
_showServiceError: function(sDetails) {
if (this._bMessageOpen) {
return;
}
this._bMessageOpen = true;
MessageBox.error(
this._sErrorText, {
id: "serviceErrorMessageBox",
details: sDetails,
styleClass: this._oComponent.getContentDensityClass(),
actions: [MessageBox.Action.CLOSE],
onClose: function() {
this._bMessageOpen = false;
}.bind(this)
}
);
}
if someone knows how to recover that value, I'll be very greatful.
Greetings.
i fixed this issue, changing this part of the code
if (oParams.response.statusCode !== "404" || (oParams.response.statusCode === 404 && oParams.response.responseText.indexOf(
"Cannot POST") === 0)) {
this._showServiceError(oParams.response);
}
}, this);
to
if (oParams.response.statusCode !== "404" || (oParams.response.statusCode === 404 && oParams.response.responseText.indexOf(
"Cannot POST") === 0)) {
this._showServiceError($(oParams.response.responseText).find("message").first().text());
}
}, this);
Check if you have HCM_LRQ_CRE BSP application in your SAP ABAP Repository, actually it is an HCM Leave Request Fiori app. You can find there DataManager-dbg.js file. Look into parseErrorMessages method, it parses SAP messages nicely. Probably you can use it as a starting point.

Increase sails bodyP

In my app (sails 0.12.0) I want to extend a limit of bytes send upon POST request. So I've followed the comments in this stackoverflow question
var skipper = require('skipper');
skipper.limit = 1024*1024*100;
middleware: {
bodyParser: skipper
}
I still get an error:
"data": {
"code": "E_EXCEEDS_UPLOAD_LIMIT",
"name": "Upload Error",
"maxBytes": 15000000,
"written": 15007474,
"message": "Upload limit of 15000000 bytes exceeded (15007474 bytes written)"
}
I've also tried to add the code below directly under module.exports.http and then I've tried to add it in the middleware only.
bodyParser: (function () {
var opts = {limit:'50mb'};
var fn;
// Default to built-in bodyParser:
fn = require('skipper');
return fn(opts);
})
My question is: Why none of these codes work and how can I increase the limit. The solution can be not elegant.
Everything that you need - set
maxBytes
attribute in object of options to upload() method of skipper Upstream.
req.file('image').upload({maxBytes: 50000000}, function (err, uploadedFiles) {
if (err) return res.serverError(err.message);
if(uploadedFiles.length > 0) {
// do with uploaded images what you want
.....
}
});

node-sqlserver, Azure Mobile Services and Azure SQL - old rows are returned even after transaction commit

I have following code on server side:
let query = `
BEGIN TRANSACTION FOO_TRAN
EXEC sp1_update ...,
EXEC sp2_insert ...,
EXEC sp3_update ...,
EXEC sp4_delete ...,
...
COMMIT TRANSACTION FOO_TRAN
SELECT 1 as [###];
`;
mssql.query(query, params, {
success: function (res) {
if (res && res.length === 1 && res[0]['###'] == 1) {
response.status(200).send({id: request.body.id});
}
}, error: (err)=>response.status(500).send(err)
});
Then client immediately requests modified content using provided id.
Problem: old data is returned for ~2-3 seconds. I tried to specify READ UNCOMMITED in subsequent SELECT, but it didn't help - old rows were mixed with new ones.
To use transactions with Azure Mobile Services you'll want to use the open method on mssql to get a connection which supports transactions. See documentation of open method here. For example:
request.service.mssql.open({
success: function(connection) {
//start a transaction
connection.beginTransaction(function(errTransaction) {
if (errTransaction) {
//handle the error and respond error
connection.close();
return;
}
//define a queryString and queryParams
connection.query(queryString, queryParams, function(errQuery, results) {
if (errQuery) {
//handle the error and respond error
connection.rollback();
connection.close();
return;
}
//success
connection.commit();
connection.close();
//respond OK
});
});
},
error: function(errOpen) {
//handle the error
}
});