Search code examples
javascriptnode.jsazure-functionsazure-cosmosdbazure-iot-hub

AzureFN - NodeJS program is not inserting rows into CosmosDB


I have the following Azure Function in NodeJS which has as trigger: IoT Hub events.

And I need to transfer the messages to cosmos DB.

module.exports = function (context, IoTHubMessage) {
  try {
    var dbName = "db";
    var collectionName = "encodedmessages";

    context.log(`JavaScript eventhub trigger function called for message array: ${IoTHubMessage}`);
    var mongoClient = require("mongodb").MongoClient;
    context.log('MongoClient created');

    mongoClient.connect("mongodb://xxx:password==@xxx.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb&retrywrites=false&maxIdleTimeMS=120000&appName=@db@",{useNewUrlParser: true, authSource: dbName}, function (err, client) {

      if(err){
        context.log(`Error occurred while connecting to DB ${err}`)
      } else{
        context.log('MongoClient connected to DB');
      }

      var collection = mongoClient.db(dbName).collection(collectionName);
      context.log('MongoClient collection retreived');
      collection.insertOne(IoTHubMessage, {w: 1});
      //collection.insertOne({"testKey": 13.56}, {w: 1});
      mongoClient.close();
      context.log(`Saved message: ${IoTHubMessage}`);
      context.done();
    });

  } catch (e){
    context.log(`Error ${e}`);
  }

  context.log('Done called');
  context.done();
};

I also have a console app sending messages to the iot hub running as explained here: https://learn.microsoft.com/en-us/azure/iot-hub/quickstart-send-telemetry-dotnet

The output is the following:

2020-10-30T12:06:41.968 [Information] JavaScript eventhub trigger function called for message array: Test Message
2020-10-30T12:06:41.972 [Information] MongoClient created
2020-10-30T12:06:41.972 [Information] Done called
2020-10-30T12:06:42.026 [Information] Executed 'Functions.ProcessEncodedMessages' (Succeeded, Id=2fcb7fa8-b194-4499-bc39-775aef86aac0, Duration=24606ms)

I dont really understand why I dont see in the logs messages in this piece of code:

if(err){ context.log(Error occurred while connecting to DB ${err}) } else{ context.log('MongoClient connected to DB'); }

Its like if its never reaching to that point, and I dont get any error regarding the connection string either.


Solution

  • I believe the insertOne function returns a promise and you're not awaiting it hence its moving to the next statement which was mongoClient.close() thereby closing the connection.

    You can re-factor your code to use ES8 async-await and post resolving the insertOne function's promise schedule the call to close the connection.

    Here's a reference from the official docs.

    const { MongoClient } = require("mongodb");
    
    module.exports = function (context, IoTHubMessage) {
        const dbName = "db";
        const collectionName = "encodedmessages";
        const connectionString = `mongodb://xxx:password==@xxx.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb&retrywrites=false&maxIdleTimeMS=120000&appName=@db@`;
        const options = {
            useNewUrlParser: true, 
            authSource: dbName
        };
    
        context.log(`JavaScript eventhub trigger function called for message array: ${IoTHubMessage}`);
        const client = new MongoClient(connectionString, options);
      try {
        context.log('MongoClient created');
        await client.connect();
        
        const database = client.db(dbName);
        const collection = database.collection(collectionName);
        
        context.log('MongoClient collection retreived');
        
        const insertResult = await collection.insertOne(IoTHubMessage, {w: 1});
        
        
        context.log(`Saved message: ${IoTHubMessage}`, insertResult);
        context.done();
        context.log('Done called');
      } catch (e){
        context.log(`Error ${e}`);
        context.done();
      } finally {
        client.close();
      }
    };