Giter VIP home page Giter VIP logo

Comments (3)

mikuso avatar mikuso commented on August 25, 2024 1

Hi - as I said, it's possible that you simply missed the opportunity to subscribe to the close event before the socket closed.

Please re-read the second half of my post.

There should not be any scenarios where a 'close' event is not sent.

from ocpp-rpc.

mikuso avatar mikuso commented on August 25, 2024

Hi sarin,

Thanks for the kind words.

It looks like there are two possible race conditions that could arise as a result of the code snippet you've provided. Allow me to explain how these can occur:

Charge point connected but showing offline in DB.

Imagine the following scenario:

  1. Charger XYZ connects to the server (let's call this Session 1).
  2. Server updates the database to reflect the charger being online.
  3. The charger disconnects uncleanly (i.e. no TCP FIN is received by the server - perhaps a cable was unplugged) so we have to wait for an idle ping timeout before the server recognises that the charger has disconnected.
  4. The charger XYZ reconnects to the server (Session 2) before the server realises that Session 1 has ended.
  5. The server once again updates the database to reflect that the charger is online.
  6. The original connection (Session 1) finally succumbs to ping timeout and the connection is dropped from the server side.
  7. The server updates the database to indicate that the charger is now offline, despite the fact that Session 2 is still online.

Here's one way you could address this problem:

Inside the RPCServer's auth handler, assign a unique session ID to the client and pass it to the accept() callback like so:

const {randomBytes} = require('crypto');

server.auth((accept, reject, handshake) => {
    const session = {};

    // create a random session ID and assign it to the session object
    session.id = randomBytes(16).toString('hex');

    // accept the client connection and assign the session object to the client
    accept(session);
});

You can then use this ID to ensure that you are only determining the charge point to be offline when the most recent session comes to an end.

So... to apply this to your code:

server.on("client", async (client) => {
    await db("chargepoints")
        .where({ id: client.identity })
        .update({
            online: true,
            sessionId: client.session.id
        });

    client.once("close", async () => {
        await db("chargepoints")
            .where({
                id: client.identity,
                sessionId: client.session.id
            })
            .update({ online: false });
    });
});

This will ensure that only the termination of the most recent session would be able to flag the charger as being offline.

Another edge case to keep in mind is what would happen if you have 2 chargers connected to the server using the same identity. Something for you to think about.

Charge point is disconnected but still marked as online in DB.

This could occur if the charger has disconnected very quickly after connecting. This could be caused by a failing proxy, a bug in the firmware, or some other unusual condition.

Imagine this scenario:

  1. Charger XYZ connects, triggering your RPCServer's 'client' event.
  2. You begin to update your database to reflect that the charger is online. This could have a variable latency (eg. maybe 50ms before the Promise resolves).
  3. During this 50ms, the charger disconnects, firing the 'close' event on the client.
  4. Once the database has been updated, you then start listening for the 'close' event on the client, but it is now too late as the client has already disconnected.
  5. The client's 'close' event will not fire again, so you will never record that the charger has gone offline.

The solution here is to start listening for the 'close' event before performing any async operations (such as updating the database). It's actually a good idea to start listening for all events you are interested in before you start doing any async operations, as you may miss events firing if you are stuck waiting on your database to respond.

I hope this helps.

from ocpp-rpc.

sarin59337 avatar sarin59337 commented on August 25, 2024

Hi Mikuso, thanks for the explanation & suggestions.

We were not aware of the possible multiple sessions. So the first issue can be solved as you suggested. But for the second issue, we never received a 'close' event. Are there any scenarios where the charger disconnects without a 'close' event?

from ocpp-rpc.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.