MongoDB Secondary Replica does not show databases - code "NotMasterNoSlaveOk" [duplicate] - ruby-on-rails

I tried mongo replica sets for the first time.
I am using ubuntu on ec2 and I booted up three instances.
I used the private IP address of each of the instances. I picked on as the primary and below is the code.
mongo --host Private IP Address
rs.initiate()
rs.add(“Private IP Address”)
rs.addArb(“Private IP Address”)
All at this point is fine. When I go to the http://ec2-xxx-xxx-xxx-xxx.compute-1.amazonaws.com:28017/_replSet site I see that I have a primary, seconday, and arbitor.
Ok, now for a test.
On the primary create a database in this is the code:
use tt
db.tt.save( { a : 123 } )
on the secondary, I then do this and get the below error:
db.tt.find()
error: { "$err" : "not master and slaveOk=false", "code" : 13435 }
I am very new to mongodb and replicates but I thought that if I do something in one, it goes to the other. So, if I add a record in one, what do I have to do to replicate across machines?

You have to set "secondary okay" mode to let the mongo shell know that you're allowing reads from a secondary. This is to protect you and your applications from performing eventually consistent reads by accident. You can do this in the shell with:
rs.secondaryOk()
After that you can query normally from secondaries.
A note about "eventual consistency": under normal circumstances, replica set secondaries have all the same data as primaries within a second or less. Under very high load, data that you've written to the primary may take a while to replicate to the secondaries. This is known as "replica lag", and reading from a lagging secondary is known as an "eventually consistent" read, because, while the newly written data will show up at some point (barring network failures, etc), it may not be immediately available.
Edit: You only need to set secondaryOk when querying from secondaries, and only once per session.

To avoid typing rs.slaveOk() every time, do this:
Create a file named replStart.js, containing one line: rs.slaveOk()
Then include --shell replStart.js when you launch the Mongo shell. Of course, if you're connecting locally to a single instance, this doesn't save any typing.

in mongodb2.0
you should type
rs.slaveOk()
in secondary mongod node

THIS IS JUST A NOTE FOR ANYONE DEALING WITH THIS PROBLEM USING THE RUBY DRIVER
I had this same problem when using the Ruby Gem.
To set slaveOk in Ruby, you just pass it as an argument when you create the client like this:
mongo_client = MongoClient.new("localhost", 27017, { slave_ok: true })
https://github.com/mongodb/mongo-ruby-driver/wiki/Tutorial#making-a-connection
mongo_client = MongoClient.new # (optional host/port args)
Notice that 'args' is the third optional argument.

WARNING: slaveOk() is deprecated and may be removed in the next major release. Please use secondaryOk() instead. rs.secondaryOk()

I got here searching for the same error, but from Node.js native driver. The answer for me was combination of answers by campeterson and Prabhat.
The issue is that readPreference setting defaults to primary, which then somehow leads to the confusing slaveOk error. My problem is that I just wan to read from my replica set from any node. I don't even connect to it as to replicaset. I just connect to any node to read from it.
Setting readPreference to primaryPreferred (or better to the ReadPreference.PRIMARY_PREFERRED constant) solved it for me. Just pass it as an option to MongoClient.connect() or to client.db() or to any find(), aggregate() or other function.
https://docs.mongodb.com/v3.0/reference/read-preference/#primaryPreferred
http://mongodb.github.io/node-mongodb-native/3.6/api/Collection.html (search readPreference)
const { MongoClient, ReadPreference } = require('mongodb');
const client = await MongoClient.connect(MONGODB_CONNECTIONSTRING, { readPreference: ReadPreference.PRIMARY_PREFERRED });

slaveOk does not work anymore. One needs to use readPreference https://docs.mongodb.com/v3.0/reference/read-preference/#primaryPreferred
e.g.
const client = new MongoClient(mongoURL + "?readPreference=primaryPreferred", { useUnifiedTopology: true, useNewUrlParser: true });

I am just adding this answer for an awkward situation from DB provider.
what happened in our case is the primary and secondary db shifted reversely (primary to secondary and vice versa) and we are getting the same error.
so please check in the configuration settings for database status which may help you.

Adding readPreference as PRIMARY
const { MongoClient, ReadPreference } = require('mongodb');
const client = new MongoClient(url, { readPreference: ReadPreference.PRIMARY_PREFERRED});
client.connect();

Related

DB connection is not closed after request ends in a NancyFx application

I'm building a Nancy web app, and using OrmLite for DB access. I noticed that every request opens up a new DB connection and doesn't close it. I thought that registering the OrmLiteConnection class in the Application container would make it application-scoped, but it looks like I'm missing something.
Here's my code (in ConfigureApplicationContainer):
container.Register<OrmLiteConnectionFactory>(new OrmLiteConnectionFactory(connectionString, SqlServerDialect.Provider));
container.Register<OrmLiteConnection>(
(cContainer, overloads) => (OrmLiteConnection) cContainer.Resolve<OrmLiteConnectionFactory>().Open());
You need to add scope to your registration(s):
container
.Register<OrmLiteConnectionFactory>(new OrmLiteConnectionFactory(connectionString, SqlServerDialect.Provider))
.AsSingleton(); // I think this is by default, but sometimes being explicit is good.
container
.Register<OrmLiteConnection>(
(cContainer, overloads) => (OrmLiteConnection) cContainer.Resolve<OrmLiteConnectionFactory>().Open())
.AsPerRequestSingleton();;
AFAIK, this will ensure the instances are disposed at the scope's end. Therefore, if you need to do more than Dispose() then you might need to find some way of supplying a delegate that can executed at that time.
I moved registration of OrmLiteConnection to ConfigureRequestContainer. Then I overrode RequestStartup and added:
pipelines.AfterRequest += (ctx) => {
//close the connection
container.Resolve<OrmLiteConnection>().Dispose();
};

Using the TYPE command inside a Redis / Lua Script

I am attempting to use the Redis TYPE command inside a Lua script (executed via EVAL)
local key_type = redis.call("TYPE", key)
According to the Redis documentation, this should return a string of "none", "zset" etc.
However the type of the returned value is a lua table. Comparing the value to a string always returns false.
I've managed to get around the problem by changing the call to
local key_type = redis.call("TYPE", key)["ok"]
This value is indeed a string and does work in string comparison commands. I am worried that this is a bug in my particular version of Redis and it will break in future versions when I upgrade.
Does anyone know if this is expected behaviour, or a bug?
The TYPE command returns a status reply (a.k.a simple string), e.g "+list\r\n".
On Redis scripting side, call is implemented by luaRedisCallCommand which performs the real Redis command behind the scenes.
Once successfully executed, this function converts the command result with redisProtocolToLuaType.
When a status reply is encountered, this function creates a Lua table with "ok" as key, and the status reply as value (see redisProtocolToLuaType_Status). So:
there is no bug,
this is why redis.call("TYPE", key) is a table (and thus you need to get the value for the "ok" key as you did, to get key's type as a string).
Note: when you directly return the table, Redis takes care to get the value associated to the "ok" key, and returns it as a status reply, e.g:
> EVAL 'return redis.call("TYPE", "foo")'
set
See this code section for more details.

how do you programmatically tell whether a mysql connection is present?

I get this error when I run mysql_real_escape_string($value).
Warning: mysql_real_escape_string() [function.mysql-real-escape-string]: Can't connect to MySQL server on 'localhost' (10061) in ...
I wrapped up the functionality in a nice class like this
class escaper
{
function __get($value)
{
//in order for this to work properly, I must have a live connection to mysql
return mysql_real_escape_string($value);
}
}
/*
//sample usage
$safe = new escaper;
$name = "O'Reilly";
echo $safe->$name
In case someone goes down that road again, let me say it upfront that Yes! I should use PDO and parametrized queries and that the above method is not that safe.
how do you programmatically tell whether a mysql connection is present?
we just don't need that.
connection is always present
Escaping being a part of the DB class.
Connect to the database is the very first thing this class doing in the constructor.
And connect resource stored in the class variable.
So, only we need is to use this variable - easy-peasy.

StructureMap 202 - Why?

OK, I'm trying to set a property on a type I'm registering with SM.
Here's the code from the registry in one of my components. This
registry is being added during the configuration from a console app.
When I try to access the EndorsementSpecs property of the instance
AutoMandatoryEndorsementAggregator object, I get the 202. What's
interesting is that I can call
GetAllInstances>() from my
console app and it resolves just fine. Is there something about
accessing this code from within OnCreation that is causing the 202? I
can see everything I expect in WhatDoIHave(). I've also tried a TypeInterceptor with the same results.
//register all open generics
cfg.ConnectImplementationsToTypesClosing(typeof
(MandatoryEndorsementSpecBase<>));
ForSingletonOf<IMandatoryEndorsementAggregator<AutoPolicy>>()
.Use<AutoMandatoryEndorsementAggregator>()
.OnCreation((context, x) =>
{
var specs =
context.GetAllInstances<MandatoryEndorsementSpecBase<AutoPolicy>>();
x.EndorsementSpecs = specs;
})
;
Sorry to deflect your real questions, but are you just trying to inject all instances of MandatoryEndorsementSpecBase into AutoMandatoryEndorsementAggregatory?
If so, you can probably get away with just making it a constructor parameter so that they are all automatically injected.
public AutoMandatoryEndorsementAggregatory(MandatoryEndorsementSpecBase<AutoPolicy>[] endorsementSpecs){
EndorsementSpecs = endorsementSpecs;
}

Is there any way to specify a service name in the app.config file?

I want to specify my service name in the app.config without needing to recomple and install/uninstall my service repeatedly.
But just retrieving service name from app.config, the service seems ignoring it. Are there any special tricks how to obtain this?
Thanks in advance.
I mean classic windows service. I don't think any code is needed here. I just want to retrieve the service name from app.config dynamically.
After searching a while on the internet and reading articles, it became clearer to me that A service name can't be specified in the app.config in so dynamic way, instead sc command can be used to perform a similar solution. You can specify other configuration variables in the app.config and use sc to rename it
sc.exe create "servicename" binPath="myservicepath.exe"
I am not sure what scenario you have in mind. You would like the name of your Windows service to change. Fair enough. When would it change?
Imagine you have found the solution and created such a Windows service. I presume in your scenario you would install it at least the first time. Then you do not want to uninstall/install it. But presumably you would like to start/stop and do other things with it. Will one of those actions cause the name of the service to change?
If so, I imagine you could launch a process that uninstalls and installs it with a different name for you transparently, based on some kind of naming logic.
I don't see how else you could do it.
Or just come up with a really generic name to cover all possibilities (which might be incredibly simple or incredibly difficult).
http://www.codeproject.com/Articles/21320/Multiple-Instance-NET-Windows-Service
<add key="ServiceName" value="I"/>
[RunInstaller(true)]
public class ServiceInstaller1 : Installer
{
internal static string ServiceNameDefault = "My Service";
internal static string ServiceName = GetConfigurationValue("ServiceName");
/// <summary>
/// Public Constructor for WindowsServiceInstaller.
/// - Put all of your Initialization code here.
/// </summary>
public ServiceInstaller1()
{
var serviceProcessInstaller = new ServiceProcessInstaller();
var serviceInstaller = new ServiceInstaller();
//# Service Account Information
serviceProcessInstaller.Account = ServiceAccount.LocalSystem;
//serviceProcessInstaller.Username = null;
//serviceProcessInstaller.Password = null;
//# Service Information
serviceInstaller.DisplayName = ServiceName;
serviceInstaller.StartType = ServiceStartMode.Manual;
//# This must be identical to the WindowsService.ServiceBase name
//# set in the constructor of WindowsService.cs
serviceInstaller.ServiceName = ServiceName;
Installers.Add(serviceProcessInstaller);
Installers.Add(serviceInstaller);
}
private static string GetConfigurationValue(string key)
{
Assembly service = Assembly.GetAssembly(typeof(Service));
Configuration config = ConfigurationManager.OpenExeConfiguration(service.Location);
if (config.AppSettings.Settings[key] != null)
return ServiceNameDefault + " " + config.AppSettings.Settings[key].Value;
else
return ServiceNameDefault;
}
}
Assuming you mean Windows Service, the answer is no. The service has to be installed in the registry, and the name is one of the registry keys.
I'm afraid that what you are trying to do its not possible. It actually seems to go against the nature of a Windows Service purpose and current behavior.
After a windows service is installed the name can't be changed without re-installing it again. What actually names the service is an element called service installer. Which by now, I assume you know what it is and where its located.
However there are ways of manipulating an installed service by using Windows Management Instrumentation (WMI). Maybe this combined with Izabela's recommendation become the right path to your solution.
I would recommend you to read the following tutorial, you might find an alternate way of achieving what you're trying to do.
http://www.serverwatch.com/tutorials/article.php/1576131/Windows-Services-Management-With-WMI-Part-1.htm

Resources