Sunday, June 23, 2019

Convert a Standalone Mongodb instance to a Replica Set on a single machine with multiple instances

This tutorial describes the process for converting a standalone instance into a replica set.

In this scenario, there is only a single machine, but we run multiple (for this example, two) mongod instances. One instance acts as PRIMARY and other instances act as SECONDARY.

Steps:- 
1. Shut down the standalone mongod instance.
2. Restart the instance. Use the --replSet option to specify the name of the new replica set.
For example, use the following command to create a new replica set 

mongod --dbpath c:\replica\rs1\data --port 27017 --dbpath c:\replica\rs1\log\mongodb.log --replSet myset


3. Connect a mongo shell to the mongod instance.
4. Use rs.initiate() to initiate the new replica set:

Start Secondary mongod instance.


We should use unique set of port and data path for each instance, otherwise we may get port binding error and data path issues. For this instance we shall use 27018 port and /replica/rs2/data data path.

mongod --dbpath c:\replica\rs2\data --port 27018 --dbpath c:\replica\rs2\log\mongodb.log --replSet myset

Add a MongoDB instance to the Replica Set.


To add the MongoDB instances, run the following command in the mongo shell
rs.add(<hostname:port>);
rs.add("localhost:27018")

Check the Status.


You may check the status of the Replica Set by running the following command
rs.status();
Now there are two members in the Replica Set, with localhost:27017 being PRIMARY and localhost:27018 being SECONDARY.

Check Replication.

Now we can check if the replication is happening correctly. Add document in primary instance, it should reflect in all replica set 

myset:PRIMARY> use Cars
switched to db Cars
myset:PRIMARY> db.Car.insertOne({ name: "Z4", brand: "BMW"})
myset:PRIMARY> 

Now check in SECONDARY instance, if this has replicated. To connect to MongoDB instance running at 27018, run the following command

mongo --port 27018

myset:SECONDARY> use Cars
switched to db Cars
myset:SECONDARY> db.Car.find();
error: { "$err" : "not master and slaveOk=false", "code" : 13435 }
myset:SECONDARY> 

Set "slave okay" mode to let the mongo shell know that We're allowing reads from a secondary. This is to protect applications from performing eventually consistent reads by accident. 
We can do this in the shell with:

rs.slaveOk()

Now find the document in secondary instance.

myset:SECONDARY> use Cars
switched to db fruits
myset:SECONDARY> db.Car.find();
"_id" : ObjectId("5a018ea7c89da78ba2076f25"), "name" : "Z4""brand" : "BMW" }
myset:SECONDARY> 

Same we can do with another instance. 

Wednesday, June 19, 2019

Why you should use ConfigureAwait(false) in library code

Await task uses the sync context

1. it captures the current syncContext before awaiting.
2. Upon task completing, it calls syncContext.Post() to resume "Where you were before"


Problem :- 
1. DeadLock

The root cause of this deadlock is due to the way await handles contexts. By default, when an incomplete Task is awaited, the current “context” is captured and used to resume the method when the Task completes. This “context” is the current SynchronizationContext unless it’s null, in which case it’s the current TaskScheduler. GUI and ASP.NET applications have a SynchronizationContext that permits only one chunk of code to run at a time. When the await completes, it attempts to execute the remainder of the async method within the captured context. But that context already has a thread in it, which is (synchronously) waiting for the async method to complete. They’re each waiting for the other, causing a deadlock

  public static class DeadlockExample
    {
        private static async Task RunAsync()
        {
            await Task.Delay(1000);
        }
        // This method causes a deadlock when called in a GUI or ASP.NET context.
        public static void Test()
        {
            // Start the delay.
            var task = Runsync();
            // Wait for the delay to complete.
            task.Wait();
        }

    }

Solution :-  we can use "await task.configurationAwait(false).

  public ConfiguredTaskAwaitable ConfigureAwait(bool continueOnCapturedContext)
    {
      return new ConfiguredTaskAwaitable(this, continueOnCapturedContext);
    }

This suppresses step 2, instead if it resumes "on thread that completed  the tasks"

Principles :- UI messgage-queue is an app global resource. To much use will hurt UI responsiveness.

Guidance:- If your method calls chatty async apis. but doesn't touch the UI, then use configurationAwait(false)

2. Performance :- By using ConfigureAwait, This enable small amount of parallelism: Some asynchronous code can run in parallel with the GUI thread instead of constantly badgering it with bits of work to do.

Kafka setup in window

Here's a step-by-step guide on how to do it : 1. Prerequisites : Before you begin, make sure you have the following prerequisites inst...