st-one-io / node-red-contrib-safe-queue

Node-RED node to securely manage work queues
Apache License 2.0
3 stars 2 forks source link

Parsing error on msgs from a HTTP end-point #50

Closed macedolfm closed 5 years ago

macedolfm commented 5 years ago

Getting the below error from a "queue out" node uppon receiving a msg from an HTTP GET end-point with following payload. If injecting the JSON directly no error occur, so it may be the msg.req/msg.res objects.

Payload: {"device_type":"PMS-100-Thermo-Pulse","device":"43ED78","time":"1538630900","data":"1d24162cb4e28900","seq_number":"1135"}

Error: {"message":"TypeError: Converting circular structure to JSON","source":{"id":"86047baa.8778a8","type":"queue in","count":1},"stack":"TypeError: Converting circular structure to JSON\n at JSON.stringify (<anonymous>)\n at FileSystem.saveMessage (C:\\Users\\Administrator\\.node-red\\node_modules\\node-red-contrib-safe-queue\\src\\FileSystem.js:378:36)\n at SafeQueueConfig.receiveMessage (C:\\Users\\Administrator\\.node-red\\node_modules\\node-red-contrib-safe-queue\\red\\safeQueue.js:219:26)\n at SafeQueueIn.<anonymous> (C:\\Users\\Administrator\\.node-red\\node_modules\\node-red-contrib-safe-queue\\red\\safeQueue.js:515:25)\n at emitOne (events.js:116:13)\n at SafeQueueIn.emit (events.js:211:7)\n at SafeQueueIn.Node.receive (C:\\Users\\Administrator\\AppData\\Roaming\\npm\\node_modules\\node-red\\red\\runtime\\nodes\\Node.js:215:14)\n at FunctionNode.Node.send (C:\\Users\\Administrator\\AppData\\Roaming\\npm\\node_modules\\node-red\\red\\runtime\\nodes\\Node.js:202:14)\n at sendResults (C:\\Users\\Administrator\\AppData\\Roaming\\npm\\node_modules\\node-red\\nodes\\core\\core\\80-function.js:52:18)\n at Object.send (C:\\Users\\Administrator\\AppData\\Roaming\\npm\\node_modules\\node-red\\nodes\\core\\core\\80-function.js:108:21)"}

msg.req: {"_readableState":{"objectMode":false,"highWaterMark":16384,"buffer":{"head":null,"tail":null,"length":0},"length":0,"pipes":null,"pipesCount":0,"flowing":null,"ended":false,"endEmitted":false,"reading":false,"sync":true,"needReadable":false,"emittedReadable":false,"readableListening":false,"resumeScheduled":false,"destroyed":false,"defaultEncoding":"utf8","awaitDrain":0,"readingMore":true,"decoder":null,"encoding":null},"readable":true,"domain":null,"_events":{},"_eventsCount":0,"socket":"[internal]","connection":"[internal]","httpVersionMajor":1,"httpVersionMinor":1,"httpVersion":"1.1","complete":false,"headers":{"host":"sigfox.ivigilant.com.br:80","accept-language":"fr","accept-encoding":"gzip,deflate","user-agent":"SIGFOX","accept-charset":"UTF-8;q=0.9,*;q=0.7"},"rawHeaders":["host","sigfox.ivigilant.com.br:80","accept-language","fr","accept-encoding","gzip,deflate","user-agent","SIGFOX","accept-charset","UTF-8;q=0.9,*;q=0.7"],"trailers":{},"rawTrailers":[],"upgrade":false,"url":"/sigfox?device_type=PMS-100-Thermo-Pulse&device=43ED78&time=1538630900&data=1d24162cb4e28900&seq_number=1135","method":"GET","statusCode":null,"statusMessage":null,"client":"[internal]","_consuming":false,"_dumped":false,"baseUrl":"","originalUrl":"/sigfox?device_type=PMS-100-Thermo-Pulse&device=43ED78&time=1538630900&data=1d24162cb4e28900&seq_number=1135","_parsedUrl":{"protocol":null,"slashes":null,"auth":null,"host":null,"port":null,"hostname":null,"hash":null,"search":"?device_type=PMS-100-Thermo-Pulse&device=43ED78&time=1538630900&data=1d24162cb4e28900&seq_number=1135","query":"device_type=PMS-100-Thermo-Pulse&device=43ED78&time=1538630900&data=1d24162cb4e28900&seq_number=1135","pathname":"/sigfox","path":"/sigfox?device_type=PMS-100-Thermo-Pulse&device=43ED78&time=1538630900&data=1d24162cb4e28900&seq_number=1135","href":"/sigfox?device_type=PMS-100-Thermo-Pulse&device=43ED78&time=1538630900&data=1d24162cb4e28900&seq_number=1135","_raw":"/sigfox?device_type=PMS-100-Thermo-Pulse&device=43ED78&time=1538630900&data=1d24162cb4e28900&seq_number=1135"},"params":{},"query":{"device_type":"PMS-100-Thermo-Pulse","device":"43ED78","time":"1538630900","data":"1d24162cb4e28900","seq_number":"1135"},"res":"[internal]","route":{"path":"/sigfox","stack":[{"name":"cookieParser","keys":[],"regexp":{"fast_star":false,"fast_slash":false},"method":"get"},{"name":"httpMiddleware","keys":[],"regexp":{"fast_star":false,"fast_slash":false},"method":"get"},{"name":"corsHandler","keys":[],"regexp":{"fast_star":false,"fast_slash":false},"method":"get"},{"name":"metricsHandler","keys":[],"regexp":{"fast_star":false,"fast_slash":false},"method":"get"},{"name":"<anonymous>","keys":[],"regexp":{"fast_star":false,"fast_slash":false},"method":"get"},{"name":"<anonymous>","keys":[],"regexp":{"fast_star":false,"fast_slash":false},"method":"get"}],"methods":{"get":true}},"cookies":{},"signedCookies":{}}

machadotiago commented 5 years ago

We could reproduce your issue here with the following simple flow:

image

The "safe-queue-in" node parses the message as soon as it's received (by using JSON.stringify) and the error is generated because the message from the "http-request" node has some circular references.

We will try to fix that but I'm not sure if it is possible.

By the way, as a workaround, if your application does not require an "http response", you can simply use a "change" node to remove the "msg.req" and "msg.res" parameters right after the "http-request" node, like in this example below: image

macedolfm commented 5 years ago

Hi,

Thanks, that´s exactly what I´ve done, removed "msg.req" and "msg.res" preserving only msg.payload, also took me sometime to figure some other fine details of the implementation like:

  1. The "queue out" node will always fire, even if we instantly provide an ACK just after "queue in" forward the msg as received wich resulted in double forwarding of the message. Only latter I realized that the "on error" forwarding of msg was in fact a safe/catch last resort mechanism in case the "queue in" node failed to persist te msg on disk so we had a last chance of processing msg before losing it forever.

  2. Also learned the hard way not to store the same msg on two different queues as the msg queue processor will get really confused. I wanted to have two queues so I could fire and control two separete "HTTP Requests" from the same "HTTP In" msg for posting telemetry & attributes that arrive mixed togheter from SIGFOX at the same "HTTP In" msg.payload.

Anyway, all solved, thank you again.

image

machadotiago commented 5 years ago

Hi, good to know that you managed to solve the problem.

I've reopened the issue since it still a problem and we are already working on a fix for that .

DiegoRampim commented 5 years ago

Hi, I changed mode of parse the received messages, now went added the library json-stringify-safe for parsing messages.

macedolfm commented 5 years ago

Valeu Diego,

Na verdade o msg.req ainda pode ser de alguma ajuda mas o msg.res de fato é só lixo uma vez que a conexão no HTTP IN já pode ter morrido qdo a msg for recuperada da fila.

Uma dúvida que tenho é se quando a mensagem é recuperada da fila e processada, se ela é gravada novamente com as modificações ou se ela sempre é recuperada da pilha no mesmo estado, pergunto isso pois no meu caso a mensagem recuperada deve gerar dois POSTS em servidores distintos (um ou outro ou os dias podem falhar) e gostaria de ter dois flags na msg para saber ao final, antes do ACK, se ambos os POSTS foram processados com sucesso e se realmente posso dar o ACK na tarefa e/ou qual das duas tarefas tem ainda que ser re-POST.

Valeu, abração, Luis

Sent from Mail for Windows 10

From: Diego Rampim Sent: Friday, October 5, 2018 4:15 PM To: netsmarttech/node-red-contrib-safe-queue Cc: Luis F. Macedo; State change Subject: Re: [netsmarttech/node-red-contrib-safe-queue] Parsing error on msgsfrom a HTTP end-point (#50)

Hi, I changed mode of parse the received messages, now went added the library json-stringify-safe for parsing messages. — You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub, or mute the thread.

DiegoRampim commented 5 years ago

Opa Luis, só para entender melhor seu flow, você precisa que as informações recebida através do HTTP IN e sejam entregues a dois servidores destino?

Se quiser me mande seu flow por email que te ajudo a trabalhar nele, drampim@gmail.com.

macedolfm commented 5 years ago

Olá Diego,

Sim, quase isso, tenho que fazer duas chamadas REST (no mesmo servidor, mas tanto faz) cada uma com parte da msg recebida do SIGFOX, é que parte da mensagem é de atributos do transmissor (bateria, voltagem, etc. onde só interessa o estado atual) e outra parte é de telemetria cujo valor ao longo tempo é relevante, o problema é que esses dados vem todos na mesma mensagem mas para arzmazen-alos eu preciso fazer o split deles e enviar cada grupo numa REST diferente e só deveria fazer o ACK da mensagem quando as DUAS RESTS retornarem 200 OK, ao mesmo tempo não é interessante ficar SEMPRE chamando as duas RESTs toda vez que UMA delas falha, o que iria gerar duplicidade de dados no servidor.

Minha primeira opção foi salvar a msg recebida em DUAS “queue in” distintas, uma para atributos e outra para telemetria mas aparentemente o “queue processor” não gostou de ter o mesmo msg_id duplicado, mesmo que em dois folder separados e não sei porque começou a misturar uma com a outra.

Então achei que de alguma forma vc estaria sempre lendo as msg pelo msg_id, então salvei a msg original numa unica “queue in” e toda vez que o “queue out” recupera a msg eu faço o split em dois REST separados, mas ai caso um deles falhasse como eu poderia avisar ao outro Node para não dar o ACK ?

E ainda tem o problema de chamar novamente a REST com o mesmo dadao que já foi aceito….enfim, o idela seria que cada “queue in” fosse realmente independente mas o problema talvez esteja no msg_id que provavelmente é utilizado internamente pelo NodeRED para cotrole de fluxo e dessa maneira haveria duplicidade de msg_id no Flow.

A unica solução que vejo seria criar uma nova msg_id para cada “queue” antes de graver a msg no disco….mas ainda tem o problema da msg no “queue in” que sinceramente eu acho que só deveria encaminhar a msg adianta em caso de “on_error”.

Deu para entender ?

Sent from Mail for Windows 10

From: Diego Rampim Sent: Friday, October 5, 2018 5:41 PM To: netsmarttech/node-red-contrib-safe-queue Cc: Luis F. Macedo; State change Subject: Re: [netsmarttech/node-red-contrib-safe-queue] Parsing error on msgsfrom a HTTP end-point (#50)

Opa Luis, só para entender melhor seu flow, você precisa que as informações recebida através do HTTP IN e sejam entregues a dois servidores destino? Se quiser me mande seu flow por email que te ajudo a trabalhar nele, drampim@gmail.com. — You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub, or mute the thread.

DiegoRampim commented 5 years ago

Entendi. Montei um flow com o que entendi, simulei o servidor com o próprio Node-RED, verifique se essa ideia te ajuda.

Do jeito que montei cada parte da mensagem fica independe, sem gerar a duplicação da mesma no caso de reenvio.

[{"id":"a5a31548.a24fb8","type":"tab","label":"Midware","disabled":false,"info":""},{"id":"36413158.5c7fde","type":"tab","label":"Servers","disabled":false,"info":""},{"id":"20ea2b00.109086","type":"queue config","z":"","name":"","storage":"fs","path":"SERVER-1","timeoutAck":"1000","startJob":true,"typeTimeout":"move-error","typeError":"move-error","retryTimeout":"","retryError":"","maxInMemory":""},{"id":"7bc95fef.e2dfe","type":"queue config","z":"","name":"","storage":"fs","path":"SERVER-2","timeoutAck":"1000","startJob":true,"typeTimeout":"move-error","typeError":"move-error","retryTimeout":"","retryError":"","maxInMemory":""},{"id":"7a3963a1.21499c","type":"ui_base","theme":{"name":"theme-light","lightTheme":{"default":"#0094CE","baseColor":"#0094CE","baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif","edited":true,"reset":false},"darkTheme":{"default":"#097479","baseColor":"#097479","baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif","edited":false},"customTheme":{"name":"Untitled Theme 1","default":"#4B7930","baseColor":"#4B7930","baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"},"themeState":{"base-color":{"default":"#0094CE","value":"#0094CE","edited":false},"page-titlebar-backgroundColor":{"value":"#0094CE","edited":false},"page-backgroundColor":{"value":"#fafafa","edited":false},"page-sidebar-backgroundColor":{"value":"#ffffff","edited":false},"group-textColor":{"value":"#1bbfff","edited":false},"group-borderColor":{"value":"#ffffff","edited":false},"group-backgroundColor":{"value":"#ffffff","edited":false},"widget-textColor":{"value":"#111111","edited":false},"widget-backgroundColor":{"value":"#0094ce","edited":false},"widget-borderColor":{"value":"#ffffff","edited":false},"base-font":{"value":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"}}},"site":{"name":"Node-RED Dashboard","hideToolbar":"false","allowSwipe":"false","dateFormat":"DD/MM/YYYY","sizes":{"sx":48,"sy":48,"gx":6,"gy":6,"cx":6,"cy":6,"px":0,"py":0}}},{"id":"53a60696.6b09e8","type":"http in","z":"a5a31548.a24fb8","name":"","url":"/teste","method":"get","upload":false,"swaggerDoc":"","x":120,"y":100,"wires":[["ec469c29.a3fea","aeab0eaf.96bea"]]},{"id":"3f251464.bca93c","type":"queue in","z":"a5a31548.a24fb8","name":"","config":"20ea2b00.109086","sendError":true,"x":560,"y":60,"wires":[["2641d5a0.c7c15a"]]},{"id":"267b5f72.07601","type":"queue in","z":"a5a31548.a24fb8","name":"","config":"7bc95fef.e2dfe","sendError":true,"x":560,"y":120,"wires":[[]]},{"id":"2641d5a0.c7c15a","type":"http response","z":"a5a31548.a24fb8","name":"","statusCode":"","headers":{},"x":770,"y":60,"wires":[]},{"id":"6ab7c2b0.fa9afc","type":"queue out","z":"a5a31548.a24fb8","name":"","config":"20ea2b00.109086","x":160,"y":220,"wires":[["2d19bd31.6e1b72"]]},{"id":"5883f148.8428c","type":"queue ack","z":"a5a31548.a24fb8","name":"","config":"20ea2b00.109086","x":760,"y":220,"wires":[]},{"id":"2d19bd31.6e1b72","type":"http request","z":"a5a31548.a24fb8","name":"POST Server 1","method":"POST","ret":"txt","url":"http://127.0.0.1:1880/server-1","tls":"","x":380,"y":220,"wires":[["3d021c4a.d5b7f4"]]},{"id":"3d021c4a.d5b7f4","type":"switch","z":"a5a31548.a24fb8","name":"Status ok","property":"statusCode","propertyType":"msg","rules":[{"t":"btwn","v":"199","vt":"num","v2":"299","v2t":"num"}],"checkall":"true","repair":false,"outputs":1,"x":560,"y":220,"wires":[["5883f148.8428c"]]},{"id":"756fb08.91df05","type":"http in","z":"36413158.5c7fde","name":"","url":"/server-1","method":"post","upload":false,"swaggerDoc":"","x":120,"y":60,"wires":[["30c34cb8.c92004","fadf7004.f806d"]]},{"id":"30c34cb8.c92004","type":"http response","z":"36413158.5c7fde","name":"","statusCode":"200","headers":{},"x":330,"y":60,"wires":[]},{"id":"fadf7004.f806d","type":"debug","z":"36413158.5c7fde","name":"SERVER 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":340,"y":100,"wires":[]},{"id":"43c6e337.75daec","type":"queue out","z":"a5a31548.a24fb8","name":"","config":"7bc95fef.e2dfe","x":160,"y":280,"wires":[["31108a13.2f5556"]]},{"id":"6d47365a.08f778","type":"queue ack","z":"a5a31548.a24fb8","name":"","config":"7bc95fef.e2dfe","x":760,"y":280,"wires":[]},{"id":"31108a13.2f5556","type":"http request","z":"a5a31548.a24fb8","name":"POST Server 2","method":"POST","ret":"txt","url":"http://127.0.0.1:1880/server-2","tls":"","x":380,"y":280,"wires":[["d4673fab.226c3"]]},{"id":"d4673fab.226c3","type":"switch","z":"a5a31548.a24fb8","name":"Status ok","property":"statusCode","propertyType":"msg","rules":[{"t":"btwn","v":"199","vt":"num","v2":"299","v2t":"num"}],"checkall":"true","repair":false,"outputs":1,"x":560,"y":280,"wires":[["6d47365a.08f778"]]},{"id":"b7d8cb08.901328","type":"queue control","z":"a5a31548.a24fb8","name":"","config":"20ea2b00.109086","operation":"queue-size","days":0,"x":330,"y":360,"wires":[[]]},{"id":"317ff7b2.179fe8","type":"queue control","z":"a5a31548.a24fb8","name":"","config":"20ea2b00.109086","operation":"done-size","days":0,"x":320,"y":440,"wires":[[]]},{"id":"4d654085.157dd","type":"queue control","z":"a5a31548.a24fb8","name":"","config":"20ea2b00.109086","operation":"error-size","days":0,"x":320,"y":520,"wires":[[]]},{"id":"43990992.5d0928","type":"inject","z":"a5a31548.a24fb8","name":"","topic":"","payload":"","payloadType":"str","repeat":"10","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":360,"wires":[["4d654085.157dd","317ff7b2.179fe8","b7d8cb08.901328"]]},{"id":"9471fd7.53956","type":"queue control","z":"a5a31548.a24fb8","name":"","config":"7bc95fef.e2dfe","operation":"queue-size","days":0,"x":790,"y":360,"wires":[[]]},{"id":"f238a3d6.37ff1","type":"queue control","z":"a5a31548.a24fb8","name":"","config":"7bc95fef.e2dfe","operation":"done-size","days":0,"x":780,"y":440,"wires":[[]]},{"id":"b0031077.5584b","type":"queue control","z":"a5a31548.a24fb8","name":"","config":"7bc95fef.e2dfe","operation":"error-size","days":0,"x":780,"y":520,"wires":[[]]},{"id":"8f57dca9.eb7ed","type":"inject","z":"a5a31548.a24fb8","name":"","topic":"","payload":"","payloadType":"str","repeat":"10","crontab":"","once":false,"onceDelay":0.1,"x":590,"y":360,"wires":[["b0031077.5584b","f238a3d6.37ff1","9471fd7.53956"]]},{"id":"866c7ef6.78293","type":"http in","z":"36413158.5c7fde","name":"","url":"/server-2","method":"post","upload":false,"swaggerDoc":"","x":120,"y":160,"wires":[["a5dda3d6.a7f54","a7c0fce9.3dda3"]]},{"id":"a5dda3d6.a7f54","type":"http response","z":"36413158.5c7fde","name":"","statusCode":"200","headers":{},"x":330,"y":160,"wires":[]},{"id":"a7c0fce9.3dda3","type":"debug","z":"36413158.5c7fde","name":"SERVER 2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":340,"y":200,"wires":[]},{"id":"f6d62081.71f","type":"queue control","z":"a5a31548.a24fb8","name":"","config":"20ea2b00.109086","operation":"resend-errors","days":0,"x":330,"y":620,"wires":[[]]},{"id":"9e02dee1.93f4c","type":"inject","z":"a5a31548.a24fb8","name":"","topic":"","payload":"","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":620,"wires":[["f6d62081.71f"]]},{"id":"39b25fa6.210f9","type":"queue control","z":"a5a31548.a24fb8","name":"","config":"7bc95fef.e2dfe","operation":"resend-errors","days":0,"x":790,"y":620,"wires":[[]]},{"id":"66d3699f.9e2c98","type":"inject","z":"a5a31548.a24fb8","name":"","topic":"","payload":"","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":590,"y":620,"wires":[["39b25fa6.210f9"]]},{"id":"ec469c29.a3fea","type":"change","z":"a5a31548.a24fb8","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.v1","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":320,"y":60,"wires":[["3f251464.bca93c"]]},{"id":"aeab0eaf.96bea","type":"change","z":"a5a31548.a24fb8","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.v2","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":320,"y":120,"wires":[["267b5f72.07601"]]}]

image

image

macedolfm commented 5 years ago

Opa Diego,

Super obrigado pela atenção.

Então, foi exatamente assim que fiz da primeira vez só que dando o debug.print no final da “msg” percebi que as vezes havia uma troca das msg no fim das filas. Explico: para enviar o POST com o HTTP Out é necessário setar o msg.payload com os dados do body, no seu exemplo vc pulou isso, mandou o payload igual para os dois “RESTs” qdo na verdade os atributos estariam no payload_v1 modificado e a telemetria no payload_v2 modificado. hei que talvez fosse um problema com as msg sendo injetadas pelos dois “queue out” com os mesmos “_msgid” como o exemplo abaixo e que talvez o NodeRED estivesse se enrolando com isso pois haveriam DUAS msg com o mesmo “_msgid” na fila de rpoecessamento, principalemnte se uma delas desse timeouot ou algo assim, pois agora não consigo fazer o erro aparecer, mas antes havia uma troca de valores em algunas campos como se houvesse essa confusão, sei lá. Vou tentar mais um pouco e se não der pau vou voltar para essa estrategia das duas queues, valeu !!!!!

Agora tenho que sair mas na volta dou mais uma mastigada nisso kkkkk

SERVER-1 {"keyMessage":"9f4a1bf7-3c06-463e-b885-a38b8f9fcd05","message":{"_msgid":"87b4da22.0a9b08"

SERVER-2 {"keyMessage":"62e48bb5-ee8a-4e05-ab6b-0f4d62040b8e","message":{"_msgid":"87b4da22.0a9b08"…..

Sent from Mail for Windows 10

From: Diego Rampim Sent: Friday, October 5, 2018 6:12 PM To: netsmarttech/node-red-contrib-safe-queue Cc: Luis F. Macedo; State change Subject: Re: [netsmarttech/node-red-contrib-safe-queue] Parsing error on msgsfrom a HTTP end-point (#50)

Entendi. Montei um flow com o que entendi, simulei o servidor com o próprio Node-RED, verifique se essa ideia te ajuda. Do jeito que montei cada parte