#!/usr/bin/env python
# (C)2002 Anansi Spaceworks
#----------------------------------------------------------
#
# Heartbeat
#	Generate an XMLRPC call to a given URL at a given
#	interval.  Utility for triggering recurring
#	activity in Zope. This uses a single long-running
#	process for frequent calls. (Unix "cron" might
#	be more appropriate for lower frequency calls, such
#	as "once daily").
#
#	The URL called should be an XML-RPC server which
#	expects the following call interface:
#
#	heartbeat(int(pid), int(interval))
#
#	It should return (via XML-RPC):
#
#	int(new_interval or 0 or -1)
#
#	A negative number means we should quit (this is
#	provided as a mechanism to deal with pruning multiple
#	instances).
#
#	If URL doesn't exist, just ignore it and try again
#	next time -- the server may be temporarily down,
#	for example, without causing a problem.
#
#----------------------------------------------------------

import os, sys, time

import xmlrpclib

if len(sys.argv) < 3:
    print "USAGE: heartbeat <url> <interval-seconds> [<logfile>]"
    sys.exit()

url      = sys.argv[1]		# URL to call
interval = int(sys.argv[2])	# Heartbeat period in seconds

if len(sys.argv) > 3 and sys.argv[3]:
  logfname = sys.argv[3]	# Filename to log to
  logging = 1
  logfile = open(logfname, 'a')
  logfile.write("%s\tHeartbeat Daemon started.\n" % time.ctime())
  logfile.close()
else:
  logging = 0
  
pid      = os.getpid()		# Process ID (given to caller)

while 1:
    time.sleep(interval)
    logtime = time.ctime()
    if logging: logfile = open(logfname, 'a')
    
    try:    server = xmlrpclib.Server(url)
    except: server = None

    if server is not None:
	try:
	    result = server.heartbeat(pid, interval)
	except:
	    if logging: logfile.write("%s\theartbeat() not found on server.\n"
	    		% logtime)
	    result = 0
	    
	if logging: logfile.write(
		"%s\tHeartbeat pid=%d interval=%d result=%d\n" % 
			(logtime, pid, interval, result))
	if result:
	    if result>0: interval = int(result)
	    else:	 break
    else:
	if logging: logfile.write("%s\tServer not responding.\n" % logtime)
    if logging: logfile.close()

# We can only get here if the server tells us to shut down.

if logging: logfile.write("""\
Heartbeat generator has received the shutdown code, 
so shutting down. Bye!
""")

if logging: logfile.close()

