问题
I'm using this mongodb3 cookbook in order to install a mongodb instance.
I'm trying to perform an script when service starts:
execute "Add Mongo Users" do
command "mongo #{host}:#{port} /tmp/mongo.setup.users.js"
subscribes :run, 'service[mongod]', :delayed
end
I'm getting this error:
==> Expected process to exit with [0], but received '1'
==> ---- Begin output of mongo localhost:30158 /tmp/mongo.setup.users.js ----
==> STDOUT: MongoDB shell version v3.4.2
==> connecting to: localhost:30158
==> 2017-06-05T07:39:48.136+0000 W NETWORK [thread1] Failed to connect to 127.0.0.1:30158, in(checking soc
ket for error after poll), reason: Connection refused
==> 2017-06-05T07:39:48.136+0000 E QUERY [thread1] Error: couldn't connect to server localhost:30158, co
nnection attempt failed :
So, as you can see, service is not running yet when command is performed (I'm getting a network error).
I've took a look on cookbook repository code. According to this peace of code, the service is started...
Any ideas?
回答1:
As triggering the start of a service does not mean that it's immediately ready to accept connections, you need to wait for a bit of time.
A common approach is to add an additional, hardcoded delay, e.g.
command "sleep 3; mongo.."
Downside: 3 seconds might be enough on machine A, but not on machine B. (So put 20sec and you've solved it for 99.9% of the cases - but didn't become a better programmer ;-)).
A better approach can be e.g. seen in the jenkins cookbook's helper library:
def wait_until_ready! Timeout.timeout(timeout, JenkinsTimeout) do begin open(endpoint) rescue SocketError, Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ENETUNREACH, Timeout::Error, OpenURI::HTTPError => e # If authentication has been enabled, the server will return an HTTP # 403. This is "OK", since it means that the server is actually # ready to accept requests. return if e.message =~ /^403/ Chef::Log.debug("Jenkins is not accepting requests - #{e.message}") sleep(0.5) retry end end rescue JenkinsTimeout raise JenkinsNotReady.new(endpoint, timeout) end
This code repeatedly tries to connect to Jenkins, until it either works or a timeout is reached. You should be able to adapt this to mongo (you could call the command and check if it succeeds, or directly connect to the TCP port as the Jenkins code does.
A way in between would be to use Chef's
retry
parameter:execute "Add Mongo Users" do command "mongo #{host}:#{port} /tmp/mongo.setup.users.js" retry 10 subscribes :run, 'service[mongod]', :delayed end
I'm not entirely sure, if it will work, as the
mongo
command probably returns the failure pretty quickly, leaving little time up to the service to start (so combine with the all-mightysleep
?). Further, depending on the command that you execute, make sure that you won't cause negative side-effects (when it can connect to the service, but fails in a later step - and the result of this is that it runs once again. Think of data corruption and friends here).
来源:https://stackoverflow.com/questions/44365961/chef-mmake-sure-a-service-is-listennig-on-network