I have the following database backup script which runs once every hour.
I recently began seeing my docked-deployed Elixir application crash with the following error message:
Crash dump is being written to: erl_crash.dump...done
2016-07-27T11:05:39.754630931Z app[web.1]: binary_alloc: Cannot allocate 124512968 bytes of memory (of type "binary").
My database has been increasing steadily and it is around 130mb now.
I use the script below to do the backup and upload to So. Are there any obvious faults here which may lead to such a memory crash?
defmodule MyApp.Backup do
require Logger
alias MyApp.{ Repo, BackupUploader, S3 }
#database System.get_env("DATABASE_URL")
#bucket Application.get_env(:arc, :bucket)
#folder "backups"
def start do
Logger.info "*** Initiating database backup ***"
backup = %BackupRequest{}
backup
|> dump_database
|> upload_to_s3
end
defp dump_database(%BackupRequest{} = backup) do
Logger.info "*** Dumping database ***"
command = "pg_dump"
args = [#database]
{data, 0} = System.cmd command, args
%{backup | data: data, status: "dumped"}
end
defp upload_to_s3(%BackupRequest{data: data} = backup) do
Logger.info "*** Uploading to S3 bucket ***"
key = get_s3_key
ExAws.S3.put_object!(#bucket, key, data)
Logger.info "*** Backup complete ***"
end
# Helpers
#
#
defp get_s3_key do
{{year, month, day}, {hour, minute, _seconds}} = :os.timestamp |> :calendar.now_to_datetime
hash = SecureRandom.urlsafe_base64(32)
date = "#{day}-#{month}-#{year}-#{hour}:#{minute}"
key = #folder <> "/#{date}_#{hash}_#{Mix.env}"
key
end
end
Related
I am using ThreadPoolExecuter for parallel execution of a function which prints statements and executes the sql. I would like to manage the print statements from the function. Eg
def Func(host,sql):
print ('Executing for %s ' %host)
SQL = Execute(host,SQL) -- connecting to DB
print SQL
main():
sql = 'show databases;'
hostList = ['abc.com','def.com','ghi.com','jkl.com']
with concurrent.futures.ThreadPoolExecutor() as executor:
future = [executor.submit(Func,acct ,host,sql) for host in hostList]
Here for 4 items in hostList it executes the thread and executes the function Func in parallel but prints results like below
Executing for abc.com
Executing for def.com
Executing for ghi.com
Executing for jkl.com
then
SQL output 1
SQL output 2
SQL output 3
SQL output 4
How I would like the function to print is like below
Executing for abc.com
SQL output 1
Executing for def.com
SQL output 1
Executing for ghi.com
SQL output 1
Executing for jkl.com
SQL output 1
If you just want to group your print statements together without reflecting the pause required to execute then you can do the following. Note that if the ONLY thing you are doing is a single print statement then you likely don't need the lock.
import concurrent.futures
import threading
import random
import time
def Func(account, host, sql, lock):
seconds = random.randint(1, 10)
time.sleep(seconds)
result = "Result of executing \"{}\" took {} seconds".format(sql, seconds)
## -------------------------------
## Probably don't need to lock if you combine these into one statement
## -------------------------------
with lock:
print('Executing for %s ' % host)
print("\t{}\n".format(result))
## -------------------------------
lock = threading.Lock()
hostList = ['abc.com','def.com','ghi.com','jkl.com']
with concurrent.futures.ThreadPoolExecutor() as executor:
future = [executor.submit(Func, "acct" , host, "somesql", lock) for host in hostList]
I have a java XPages domino application that's running on my server and serves as an API for handling the Rooms & Resoruces database remotely (the main role is obtaining reservations for a set of rooms and updating it periodically).
Everything was fine when testing, but once I put the app on my production server, I got a crash after some time:
Domino version: Release 10.0.1FP3 August 09, 2019
OS Version: Windows/2016 10.0 [64-bit]
Error Message = PANIC: semaphore invalid or not allocated
SharedDPoolSize = 33554432
FaultRecovery = 0x00010012
Cleanup Script Timeout= 600
Crash Limits = 3 crashes in 5 minutes
StaticHang = Virtual Thread [ nHTTP: 0674: 0011] (Native thread [ nHTTP: 0674: 145c]) (0x674/0x11/0x170000145C)
ConfigFileSem = ( SEM:#0:0x1520000010D) n=0, wcnt=-1, Users=-1, Owner=[ : 0000]
FDSem = ( RWSEM:#53:0x410f) rdcnt=-1, refcnt=0 Writer=[ : 0000], n=53, wcnt=-1, Users=0, Owner=[ : 0000]
<## ------ Notes Data -> OS Data -> Semaphores -> SEM Info (Time 10:34:34) ------ ##>
SpinLockIterations = 1500
FirstFreeSem = 819
SemTableSize = 827
############################################################
### thread 46/89: [ nHTTP: 0674: 145c] FATAL THREAD (Panic)
### FP=0xF3AC3F61E8, PC=0x7FFFC6DD5AC4, SP=0xF3AC3F61E8
### stkbase=0xF3AC400000, total stksize=1048576, used stksize=40472
### EAX=0x00000004, EBX=0x00000000, ECX=0x00001c6c, EDX=0x00000000
### ESI=0x000927c0, EDI=0x00001c6c, CS=0x00000033, SS=0x0000002b
### DS=0x00000000, ES=0x00000000, FS=0x00000000, GS=0x00000000 Flags=0x1700000246
############################################################
[ 1] 0x7FFFC6DD5AC4 ntdll.ZwWaitForSingleObject+20 (10,0,0,F3AC3F6300)
[ 2] 0x7FFFC3464ABF KERNELBASE.WaitForSingleObjectEx+143 (10,F3AC3F69B0,7FFF00000000,1c6c)
#[ 3] 0x7FFFB326DAD0 nnotes.OSRunExternalScript+1808 (5,0,424,0)
#[ 4] 0x7FFFB3269E9C nnotes.FRTerminateWindowsResources+1532 (5,23B45D80D50,0,1)
#[ 5] 0x7FFFB326BA23 nnotes.OSFaultCleanupExt+1395 (0,7f60,0,F3AC3F7C70)
#[ 6] 0x7FFFB326B4A7 nnotes.OSFaultCleanup+23 (7f60,7FFFB3DE7E30,0,200000000)
#[ 7] 0x7FFFB32D6D76 nnotes.OSNTUnhandledExceptionFilter+390 (F3AC3F7B50,7FFFB485A818,F3AC3F7C70,FFFFEB865BDB003)
#[ 8] 0x7FFFB326E70A nnotes.Panic+1066 (5dc,125851500347E41,7FF786A7B4A0,23B1D91F9A8)
#[ 9] 0x7FFFB329FDD6 nnotes.OSLockSemInt+70 (23B1D91F9A4,145c,7FF786A84578,7FF786A84578)
#[10] 0x7FFFB32A04ED nnotes.OSLockWriteSem+77 (23B1D92AA18,7FF786A84578,23B14EA41B0,7FF786A84578)
#[11] 0x7FFFAC74DDC1 nlsxbe.ANDatabase::ANDRemoveCalendar+33 (23B1D92AA18,7FF786A84578,0,23B18FFCBA8)
#[12] 0x7FFFAC881CBB nlsxbe.ANCalendar::`scalar deleting destructor'+91 (7FF786A84578,23B1BB6FC78,0,1)
#[13] 0x7FFFAC7FFAF7 nlsxbe.Java_lotus_domino_local_NotesBase_RecycleObject2+471 (23B159C7A00,23B1BB6FC78,23B1BB6FC70,0)
#[14] 0x7FFFAC7FF91A nlsxbe.Java_lotus_domino_local_NotesBase_RecycleObject+42 (23B159C7A00,23B1BB6FC78,23B1BB6FC70,23B159C7A00)
Most of the operations rely on searching for a room by it's internet address in the $Rooms view of names.nsf, then heading to its adequate RnR database and getting all reservation documents for that specific room. Sometimes (although very rarely) I also open the users calendar and create/update reservations.
At first I thought it's caused by some memory leak or something, I went through all the code and recycled() everything I could find (and I found some places with obvious handle leaks), but it didn't help at all.
What bothers me is that the crashes happened at almost identical hours (4 days later, several minutes after 10AM).
What can be the cause of this crash? I'm not good at reading dump data, but I can see that the first call from the fatal stack calls list is an RecycleObject, followed by some calendar related things.
I have no idea where I should look in my code, why would even recycle crash the server? Does the ANCalendar suggest that I shouldn't look at code that's accessing the database directly, but rather opening users calendar?
Update
Studying the crash logs, I managed to find out the place where the crash occured. It's my appointment creation code, which uses NotesCalendar.createEntry() on the users calendar. The code is like this:
Session session = reDatabase.getParent();
Name nnOrganizer = session.createName(session.getEffectiveUserName());
String organizerEmail = "";
DirectoryNavigator nav = session.getDirectory().lookupNames("$Users", nnOrganizer.getCommon(), "InternetAddress");
if(nav.findFirstMatch() && !nav.getFirstItemValue().isEmpty()) {
organizerEmail = (String)nav.getFirstItemValue().get(0);
}
Recycler.recycle(nav);
Name nnResource = session.createName(roomName);
DbDirectory dir = session.getDbDirectory(session.getServerName());
Database mdb = dir.openMailDatabase();
NotesCalendar cal = session.getCalendar(mdb);
String dStart = DateUtil.formatICalendar(dtStart);
String dEnd = DateUtil.formatICalendar(dtEnd);
String iCalEntry = "BEGIN:VCALENDAR\n" +
// Rest of iCalendar string goes here
iCalEntry += "END:VEVENT\n" +
"END:VCALENDAR\n";
cal.setAutoSendNotices(true);
String apptUNID ="";
try {
NotesCalendarEntry entry = cal.createEntry(iCalEntry);
Document doc = entry.getAsDocument();
apptUNID = doc.getItemValueString("ApptUNID");
Recycler.recycle(doc, entry);
} catch (NotesException ex) {
System.out.println("Couldn't create appointment!: " + ex.toString());
throw ex;
} finally {
Recycler.recycle(mdb, cal, nnOrganizer, nnResource, dir, reDatabase, session);
}
return apptUNID; // return the UNID of the created entry (if any)
Considering the fatal call stack starts with an RecycleObject call, is there anything wrong in my recycling here? Can I recycle the calendar entry directly after creating it? It's still kinda confusing to me, but this code works well on my test server. Is there anything wrong about it?
This is the last code that's being executed when creating an appointment, a HTTP response with the apptUNID is made directly after calling the above function.
What I'm trying to do
The below script loops through every item in an Array of data streams and requests a summary value for output to a text file. This external request is by far the most expensive part of the process, and so I am now using a Runspacepool to run multiple (5) requests in parallel, and whichever finishes first outputs its results.
These requests all write to a synchronised hashtable, $hash, which holds a running total ($hash.counter) and tracks which thread ($hash.thread) is updating the total and a .txt output file, to avoid potential write collisions.
What isn't working
Each thread is able to update the counter easily enough $hash.counter+=$r, but when I try and Read the value into an Add-Content statement:
Add-Content C:\Temp\test.txt "$hash.counter|$r|$p|$ThreadID"
it adds an object reference rather than a number:
System.Collections.Hashtable+SyncHashtable.counter|123|MyStreamName|21252
And so I've ended up passing the counter through a temporary variable that can be used in the string:
[int]$t = $hash.counter+0
Add-Content C:\Temp\test.txt "$t|$r|$p|$ThreadID"
Which does output the true total:
14565423|123|MyStreamName|21252
What I'm asking
Is it possible to remove this temporary variable and output directly from the hashtable? Why does the object reference have a '+' in the middle?
I've had to add logic to 'lock' the hashtable to prevent data collisions. Should this be necessary? I'd been told that synchronised hashtables were supposed to be thread-safe for R/W operations, but without this logic my counter doesn't reach the correct total.
Full code for the loop itself below - I've left out setup of the Runspacepool etc
ForEach($i in $Array){
# Save down the data stream name and create parameter list for passing to the new job
$p = $i.Point.Name
$parameters = #{
hash = $hash
conn = $Conn
p = $p
}
# Instantiate new powershell runspace and send a script to it
$PowerShell = [powershell]::Create()
$PowerShell.RunspacePool = $RunspacePool
[void]$Powershell.AddScript({
# Receive parameter list, retrieve threadid
Param (
$hash,
$conn,
$p
)
$ThreadID = [appdomain]::GetCurrentThreadId()
# Send data request to the PI Data Archive using the existing connection
$q = Get-something (actual code removed)
[int]$r = $q.Values.Values[0].Value
# Lock out other threads from writing to the hashtable and output file to prevent collisions
# If the thread isn't locked, attempt to lock it. If it is locked, sleep for 1ms and try again. Tracked by synchronised Hashtable.
Do{
if($hash.thread -eq 0){
$hash.thread = $ThreadID
}
# Sleep for 1ms and check that the lock wasn't overwritten by another parallel thread.
Start-Sleep -Milliseconds 1
}Until($hash.thread -eq $ThreadID)
# Increment the synchronised hash counter. Save the new result to a temporary variable (can't figure out how to get the hash counter itself to output to the file)
$hash.counter+=$r
[int]$t = $hash.counter+0
# Write to output file new counter total, result, pointName and threadID
Add-Content C:\Temp\test.txt "$t|$r|$p|$ThreadID"
# release lock on the hashtable and output file
$hash.thread = 0
})
# Add parameter list to instance (matching param() list from the script. Invoke the new instance and save a handle for closing it
[void]$Powershell.AddParameters($parameters)
$Handle = $PowerShell.BeginInvoke()
# Save down the handle into the $jobs list for closing the instances afterwards
$temp = [PSCustomObject]#{
PowerShell=$Powershell
Handle=$Handle
}
[void]$jobs.Add($Temp)
}
I am trying to change the directory of the couch database. I am using a python script to import a csv file to the CouchDB. Script is running ok. Here it is just in case:
from couchdbkit import Server, Database
from couchdbkit.loaders import FileSystemDocsLoader
from csv import DictReader
import sys, subprocess, math, os
def parseDoc(doc):
for k,v in doc.items():
if (isinstance(v,str)):
#print k, v, v.isdigit()
# #see if this string is really an int or a float
if v.isdigit()==True: #int
doc[k] = int(v)
else: #try a float
try:
if math.isnan(float(v))==False:
doc[k] = float(v)
except:
pass
return doc
def upload(db, docs):
db.bulk_save(docs)
del docs
return list()
def uploadFile(fname, dbname):
#connect to the db
theServer = Server()
db = theServer.get_or_create_db(dbname)
#loop on file for upload
reader = DictReader(open(fname, 'rU'), dialect = 'excel')
docs = list()
checkpoint = 100
i = 0
for doc in reader:
newdoc = parseDoc(doc)
docs.append(newdoc)
if len(docs)%checkpoint==0:
docs = upload(db,docs)
i += 1
print 'Number : %d' %i
#don't forget the last batch
docs = upload(db,docs)
if __name__=='__main__':
x = '/media/volume1/Crimes_-_2001_to_present.csv'
filename = x
dbname = 'test'
uploadFile(filename, dbname)
I saw plenty posts on how to change the directory for appending the database. If I leave the /etc/couchdb/local.ini as it is (original after installation) the script is appending data to the default directory /var/lib/couchdb/1.0.1/. When I modify the local.ini to store the database to another disk:
database_dir = /media/volume1
view_index_dir = /media/volume1
and after the reboot of the CouchDB service I get this error :
restkit.errors.RequestError: socket.error: [Errno 111] Connection refused
I have checked the open sockets (couchdb uses 5984 as default) and it is not opened. But I get no errors when I start CouchDB service.
Any ideas how to fix it ?
I think the error may be due to you have changed the directory location in Local.ini but when you are trying to make new connection to existing database, it cannot find it there.
So move the database_name.couch file to new location which you can put in local.ini and then try to make a connection. I think this should work.
Can any one help me creating a zip file out of two files one a excel and one a pdf. Im doing this without the Archive::zip because I can not install it. I am trying to go through the directory and pick up two files an excel and pdf and then zip them and send an error message or alert that says it has been zipped.
sub monthly_report_in {
### configure local variables
$StatusP="false";
$StatusX="false";
local $id,$pw,$tpwd_id,$geek_pw,$reportm_date,$file_count,$geg_id,$geg_pw,$month_abbrv;
local $org1="bfn";
local $org2="geg";
local $db_server_name=" ";
local $home_dir=" ";
local $archive_dir=" ";
local $smb_server="";
local $smb_folder="";
local $smb_folder="";
local $reportm_temp="";
local $input_name2="RegistrationStatsexcel.xls";
local $zip_input_file="RegistrationByCity*.*";
############################################################
# clean up and create file names #
# gets the date, month, and year. #
#Then creates zipped file named montly.month.year.zip #
############################################################
get_reportm_date($reportm_temp,$reportm_date);
get_month_abbrv($month_abbrv);
get_year($year);
local $file_folder_name="$db_server_name"."."."$reportm_date"."."monthly";
local $sftp_dir="";
local $zipped_file="monthly_statsreport.$month_abbrv"."$year".".zip";
##############################################################
# configure email message content #
# sends user the message that the file has been transferred #
# or an error message that says there were no files #
##############################################################
local $send_mail="email addy";
local $good_subject="$zipped_file file transferred to server: $DATE";
local $good_message="$good_subject";
local $error_messsage1="Error! No Monthly Reports Found: $DATE";
local $error_message1="No monthly reports were found.'\n\n' Contact The Help Desk.'\n\n'script name: $SCRIPT";
local $smb_subject=" $zipped_file transfered to server ";
local $smb_message="$zipped_input_file transferred to server $smb_folder\n";
local $zero_subject = "Monthly Stats files are 0 bytes: $DATE";
local $zero_message = "Monthly report Stats files are 0 bytes in size.\n\n Please Contact the Help Desk .";
#########################################################
#creates new directory and changes to new directory #
#get the ID and password for the organization #
#########################################################
mkdir($current_dir);
chdir($current_dir);
get_id_and_pw($org1,$id,$pw);
##########################################################
#smb transfer and archive pdf & excel file #
##########################################################
checkif_fileexists($current_dir,$pdf_ext,$StatusP,$error_message,$good_message);
checkif_fileexists($current_dir,$xls_ext,$StatusX,$error_message,$good_message);
print "---$StatusP---\n";
if (($StatusP =~ "false") && ($StatusX =~ "false")) {
good_mail($error_message,$error_subject1,$send_mail);
}
elseif (($StatusP =~ "zero") && ($StatusX =~ "true")) {
good_mail($good_message,$good_subject,$send_mail);
do_zip_files($current_dir,$zip_input_file);
get_id_and_pw($org2,$geg_id,$geg_pw,$smb_server,$smb_folder,$input_file);
smb_put($current_dir,$geg_id,$geg_pw,$smb_server,$smb_folder,$zip_folder,$zip_input_file);
do_move($current_dir,$zip_input_file,$archive_dir,$zip_input_file);
good_mail($smb_message,$smb_subject,$send_mail);
}
else {
### if pdf file exists, this will transfer the file and notify users
if ($StatusP =~ "true") {
do_zip_files($org2,$geg_id,$geg_pw,$smb_server,$smb_folder,$input_folder);
local $error_subject_pdf="$input_file2 report not found: $DATE";
local $error_subject_message1a="monthly report $input_file2 was not found today. 'n\n\'Compressed $input_file has been transferrd to $smb_server $smb_folder.'n\n\' Please Contact
The Help check $SCRIPT";
good_mail($error_message1a,$error_subject1a,$send_mail);
}
elseif ($StatusP =! "true");{
do_zip_files($current_dir,$pdf_ext,$input_file2);
get_id_and_pw($org2,$geg_id,$geg_id,$geg_pw);
smb_put($current_dir,$geg_id,$geg_pw,$smb_server,$smb_folder,$input_file2);
do_move($current_dir,$zip_input_file,$archive_dir,$input_file2);
local $error_subject2="$input_file1 report not found: $DATE";
local $error_message2="Monthly report $input_file1 was not found today. 'n\n\' Please Contact The Help Desk $SCRIPT";
good_mail($error_message1,$error_subject1,$send_mail);
}
}
chdir($home_dir);
###
}
This isn't really an answer to your question, but it is way too big for a comment and should help you towards a solution.
All I can do is offer a better-formatted version of your subroutine. I hope you can see how much easier it is to read?
As I said in my comment, local is almost never the right thing to use. You should also write very small sections of code and test thoroughly as you write more. If you create a whole subroutine like that then it is pretty much bound to be wrong.
Once more thing, please don't just submit what I've written. I have no idea whether any of it is correct, and it is still a very lazy piece of programming. You should start by making sure that your subroutine is even being called, with just
sub monthly_report_in {
print "entered 'monthly_report_in'\n";
}
and add functionality incrementally from there.
Here's the reformat. Please treat it with suspicion
sub monthly_report_in {
### Configure local variables
$StatusP = 'false';
$StatusX = 'false';
my ($id, $pw, $tpwd_id, $geek_pw, $reportm_date, $file_count, $geg_id, $geg_pw, $month_abbrv);
my ($org1, $org2) = qw/ bfn geg /;
my $db_server_name = ' ';
my $home_dir = ' ';
my $archive_dir = ' ';
my $smb_server = '';
my $smb_folder = '';
my $smb_folder = '';
my $reportm_temp = '';
my $input_name2 = 'RegistrationStatsexcel.xls';
my $zip_input_file = 'RegistrationByCity*.*';
############################################################
# clean up and create file names #
# gets the date, month, and year. #
# Then creates zipped file named montly.month.year.zip #
############################################################
get_reportm_date($reportm_temp, $reportm_date);
get_month_abbrv($month_abbrv);
get_year($year);
my $file_folder_name = "${db_server_name}.${reportm_date}.monthly";
my $sftp_dir = '';
my $zipped_file = "monthly_statsreport.${month_abbrv}${year}.zip";
##############################################################
# configure email message content #
# sends user the message that the file has been transferred #
# or an error message that says there were no files #
##############################################################
my $send_mail = 'email addy';
my $good_subject = "$zipped_file file transferred to server: $DATE";
my $good_message = $good_subject;
my $error_messsage1 = "Error! No Monthly Reports Found: $DATE";
my $error_message1 = "No monthly reports were found.\n\nContact The Help Desk.\n\nScript name: $SCRIPT";
my $smb_subject = "${zipped_file} transfered to server ";
my $smb_message = "${zipped_input_file} transferred to server ${smb_folder}\n";
my $zero_subject = "Monthly Stats files are 0 bytes: $DATE";
my $zero_message = "Monthly report Stats files are 0 bytes in size.\n\nPlease Contact the Help Desk.";
#########################################################
# creates new directory and changes to new directory #
# get the ID and password for the organization #
#########################################################
mkdir($current_dir);
chdir($current_dir);
get_id_and_pw($org1, $id, $pw);
##########################################################
# smb transfer and archive pdf & excel file #
##########################################################
checkif_fileexists($current_dir, $pdf_ext, $StatusP, $error_message, $good_message);
checkif_fileexists($current_dir, $xls_ext, $StatusX, $error_message, $good_message);
print "---${StatusP}---\n";
if ( $StatusP eq 'false' and $StatusX eq 'false') {
good_mail($error_message, $error_subject1, $send_mail);
}
elsif ($StatusP eq 'zero' and $StatusX eq 'true') {
good_mail($good_message, $good_subject, $send_mail);
do_zip_files($current_dir, $zip_input_file);
get_id_and_pw($org2, $geg_id, $geg_pw, $smb_server, $smb_folder, $input_file);
smb_put($current_dir, $geg_id, $geg_pw, $smb_server, $smb_folder, $zip_folder, $zip_input_file);
do_move($current_dir, $zip_input_file, $archive_dir, $zip_input_file);
good_mail($smb_message, $smb_subject, $send_mail);
}
else {
### If the PDF file exists, this will transfer the file and notify users
if ($StatusP eq 'true') {
do_zip_files($org2, $geg_id, $geg_pw, $smb_server, $smb_folder, $input_folder);
my $error_subject_pdf = "$input_file2 report not found: $DATE";
my $error_subject_message1a = "monthly report ${input_file2} was not found today.n\n\Compressed ${input_file} has been transferred to ${smb_server} ${smb_folder}.n\nPlease Contact
The Help check $SCRIPT";
good_mail($error_message1a, $error_subject1a, $send_mail);
}
elsif ($StatusP ne 'true') {
do_zip_files($current_dir, $pdf_ext, $input_file2);
get_id_and_pw($org2, $geg_id, $geg_id, $geg_pw);
smb_put(
$current_dir, $geg_id, $geg_pw,
$smb_server, $smb_folder, $input_file2
);
do_move($current_dir, $zip_input_file, $archive_dir, $input_file2);
my $error_subject2 = "${input_file1} report not found: $DATE";
my $error_message2 = "Monthly report ${input_file1} was not found today.n\nPlease Contact The Help Desk $SCRIPT";
good_mail($error_message1, $error_subject1, $send_mail);
}
}
chdir $home_dir;
}