CHAPTER 10

image

Automating Jobs with cron

In almost every type of Linux/Solaris environment—from development to production—DBAs rely heavily on automating tasks such as database backups, monitoring, and maintenance jobs. Automating routine tasks allows DBAs to be much more effective and productive. Automated environments inherently run more smoothly and efficiently than manually administered systems.

This chapter focuses on showing you how to leverage the cron job scheduler. The cron scheduling tool, which is universally available on Linux/Solaris systems, is accessible and easy to use. For these reasons, this utility is frequently chosen by DBAs to automate database jobs. Because cron is heavily used by DBAs, developers, and SAs, it is mandatory to have a working knowledge of this tool.

This chapter builds on your knowledge of Linux/Solaris OS commands, editing files, and shell scripting. You’ll need this skill set to automate your database surroundings. You should be able to extend the following recipes to meet the automation requirements of your environment.

10-1. Enabling Access to Schedule Jobs

Problem

As the oracle OS user, you’re attempting to add an entry to the cron table and you receive the following error message:

You (oracle) are not allowed to use this program (crontab)

You want to grant access to the oracle user to use the crontab utility.

Solution

As the root user, add oracle to the /etc/cron.allow file with the echo command:

# echo oracle >> /etc/cron.allow

Once the oracle entry is added to the /etc/cron.allow file, you can use the crontab utility to schedule a job.

Image Note  You can also use an editing utility (such as vi) to add an entry to this file.

How It Works

The root user can always schedule jobs with the crontab utility, but other users must be listed in the /etc/cron.allow file. If the /etc/cron.allow file does not exist, the OS user must not appear in the /etc/cron.deny file. If neither the /etc/cron.allow nor the /etc/ cron.deny file exists, only the root user can access the crontab utility.

Image Note  On Solaris systems, the cron.allow and cron.deny files are located in the /etc/cron.d directory.

The cron program is a job-scheduling utility that is ubiquitous in Linux/UNIX environments. This tool derives its name from chronos (the Greek word for time). The cron (the geek word for scheduler) tool allows you to schedule scripts or commands to run at a specified time and repeat at a designated frequency.

When your server boots up, a cron background process is automatically started that manages all cron jobs on the system. On Linux systems, the cron background process is also known as the cron daemon. This process is started on system startup by the /etc/init.d/crond script. You can check to see whether the cron daemon process is running with the ps command:

$ ps -ef | grep crond | grep -v grep
root    3049    1 0 Aug02 ?     00:00:00 crond

On Linux systems, you can verify the status of the cron daemon using the service command:

$ /sbin/service crond status
crond (pid 3049) is running...

On Solaris systems, you can verify that a cron service is running via the svcs (service status) command. This line of code prints out the services and filters the output via grep:

$ svcs -a | grep cron
online         Aug_13   svc:/system/cron:default

On Linux systems, the root user uses several files and directories when executing system cron jobs. The /etc/crontab file contains commands to run system cron jobs. Here’s a typical listing of the contents of the /etc/crontab file:

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly

This /etc/crontab file uses the run-parts utility to run scripts located in the following directories: /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly, and /etc/cron.monthly. If there is a system utility that has to run other than on an hourly, daily, weekly, or monthly basis, it can be placed in the /etc/cron.d directory.

Each user can create a crontab (also known as a cron table) file, which contains the list of programs that you want to run at a specific time and interval. This file is usually located in the /var/spool/cron directory (on Solaris systems, look in /var/spool/cron/crontabs). For every user who creates a cron table, there is a file in the /var/spool/cron directory named after that user.

The cron background process is somewhat idle. It wakes up once every minute and checks /etc/crontab, /etc/cron.d, and the user cron table files; and determines whether there are any jobs that have to be executed.

10-2. Editing the cron Table

Problem

You have the following RMAN backup code stored in a file named rmanback.bsh in the /home/oracle/bin directory:

#!/bin/bash
ORACLE_SID=TRG
ORACLE_HOME=/orahome/app/oracle/product/12.1.0.2/db_1
PATH=$PATH:$ORACLE_HOME/bin
#
rman target / <<EOF
backup database;
EOF
exit 0

You want to have a database backup script run automatically at 11:05 p.m. every night.

Solution

To schedule a job, you must add a line in your cron table that specifies the time you want the job to execute. You can edit your cron table directly with the -e (editor) option of the crontab command:

$ crontab -e

If you’re presented with a random number and a blank prompt when you first edit your cron table, your default editor is probably ed, not vi or vim. If you are in ed rather than vi, set your EDITOR OS variable to be vi:

$ export EDITOR=vi

When issuing the crontab -e command, you will be presented with a file to edit: cron table (or crontab). To schedule a script named rmanback.bsh (located in the /home/oracle/bin directory) to run daily at 11:05 p.m., enter the following line into your cron table (more on the cron syntax coming in recipe 10-3):

5 23 * * * /home/oracle/bin/rmanback.bsh

Exit the cron table file. If your default editor is vi, type :wq to exit. When you exit crontab, your cron table is saved for you. To view your cron entries, use the -l (list) option of the crontab command:

$ crontab -l

You should see this line:

5 23 * * * /home/oracle/bin/rmanback.bsh

The prior line indicates that you have successfully scheduled the file rmanback.bsh (located in /home/oracle/bin) to run daily at 23:05 (in 24-hour clock time/military time).

How It Works

Ensure that you become comfortable editing the cron table because you’ll modify it quite often as your automation requirements change. The most common way to modify the cron table is with the crontab -e command.

Loading the cron Table from a File

Another method for modifying your cron table is to load it directly with a file name using the following syntax:

$ crontab <filename>

With the previous line of code, the crontab utility will load the contents of the specified file into your cron table. We recommend that you perform the following steps when modifying your cron table with this method:

  1. Create a file with the contents of your existing cron table:
    $ crontab -l > mycron.txt
  2. Make an additional copy of your cron table before you edit it so that you can revert to the original if you introduce errors and can’t readily figure out what’s incorrect. It also provides an audit trail of changes to your cron table:
    $ cp mycron.txt mycron.jul29.txt
  3. You can now edit the mycron.txt file with your favorite text editor:
    $ vi mycron.txt
  4. To schedule a script named rmanback.bsh to run daily at 11:05 p.m., enter the following into the file:
    5 23 * * * /home/oracle/bin/rmanback.bsh
  5. When you finish making edits, load the crontab back, as shown here:
    $ crontab mycron.txt

If your file doesn’t conform to the cron syntax, you’ll receive an error such as the following:

"mycron.txt":6: bad day-of-week
errors in crontab file, can’t install.

In this situation, either correct the syntax error or reload the original copy of the cron table.

Removing the cron Table

You can completely remove your cron table with the -r option, although you’ll rarely (if ever) use it. Having said that, note that the following will completely remove your cron table:

$ crontab -r

Just to emphasize this point, the -r option is for remove, not read. Don’t make the mistake of accidentally removing an entire cron table when you simply want to edit it. Before using the -r option, save your cron table in a text file:

$ crontab -l > cron.june10.txt

That way, you can refer to the saved file if you didn’t intend to delete your cron table. It’s a best practice to save the cron table before you edit it. We’ve worked in numerous environments in which a DBA or developer accidentally removed a cron table or erroneously removed entries. Without a backup, you’ll probably have a hard time remembering exactly what was in the cron table before the change was made.

Automating the cron Table Backup

As mentioned in the previous section, consider making a backup of the contents of the cron table before you edit it. Some DBAs have cron automatically create a backup of the contents of the cron table. Consider adding this line to your cron table (the cron syntax is described next in recipe 10-3):

* * 1 * * crontab -l > /home/oracle/scripts/crontab.$(date +\%m).txt

For the prior entry to work, the directory of /home/oracle/scripts must exist. The crontab -l command will save the contents of the cron table into a text file. The name of the file will contain a numeric number that corresponds to the current month (e.g., crontab.01.txt, ..., crontab.12.txt). It will create a copy of the contents of your cron table on the first of each month (see recipe 10-6 for more details on redirecting cron output to a file).

10-3. Understanding cron Table Entries

Problem

You’ve seen an example of a cron table entry such as the following:

5 23 * * * /home/oracle/bin/rmanback.bsh

Before you add your own entries, you want some background information about how to interpret the preceding line.

Solution

Your cron table is a list of numbers and commands that the cron background process will run at a specified time and schedule. The crontab utility expects entries to follow a well-defined format. Each entry in the crontab is a single line composed of six fields (it is never split into multiple lines). The first five fields specify the execution time and frequency, and the sixth field consists of OS commands or scripts to be executed. Here’s a sample of the format:

min hr dayOfMonth monthOfYear dayOfWeek commandsOrScripts

Table 10-1 describes each field in further detail.

Table 10-1. cron Table Column Descriptions and Allowed Values

Field

Description

Allowed Values

Min

Minute of the hour

0-59, or *

Hr

Hour of the day (in 24-hour format)

0-23, or *

dayOfMonth

Day of the month

1-31, or *

monthOfYear

Month of the year

1-12, or *

dayOfWeek

Day of the week

0-6, or *; depending on version, a 0 can also be specified by a 7

commandsOrScripts

OS commands or scripts

Any combination of commands or scripts

Each entry, which is usually specified with a number, can also be an asterisk (*), which indicates that all possible values are in effect. For example, the following line of code instructs cron to send an email saying “wake up” at 12:05 p.m. every day of the month, each month, and each day of the week:

05 12 * * * echo "wake up" | mailx -s "wake up" [email protected]

Each of the first five entries can be separated by commas or hyphens. A comma indicates multiple values for an entry, whereas a hyphen indicates a range of values. For example, the following entry sends an email saying “wake up” every half hour, from 8 a.m. to 4:30 p.m., Monday through Friday:

0,30 8-16 * * 1-5 echo "wake up" | mailx -s "wake up" [email protected]

The fourth column (month of the year) and fifth column (day of the week) can be represented with numeric values or by three-letter abbreviations. For example, the following entry in the crontab uses three-letter abbreviations for months and days:

0,30 8-16 * Jan-Dec Mon-Fri echo "wake up" | mailx -s "wake up" [email protected]

On some OS versions, you can skip a value within a range by following the entry with /<integer>. For example, if you want to run a job every other minute, use 0-59/2 in the minute column. You can also use a slash (/) with an asterisk to skip values. For example, to run a job every fourth minute, use */4 in the minute column. You can do similarly for every fourth hour */4 (00, 04, 08, 12, 16, 20).

The sixth field in the cron table entry can be a combination of commands or shell scripts. For example, the following cron entry runs the rmanback.bsh shell script (located in the /home/oracle/bin directory) daily at 4:00 a.m.:

0 4 * * * /home/oracle/bin/rmanback.bsh

Lines that start with a # are comments in the cron table. In other words, any text entered after # is ignored by cron. For example, the following comment is usually added as the first line of the cron table to provide a quick syntax guide of the required format for subsequent entries:

# min(0-59) hr(0-23) dayofMonth(1-31) monthofYear(1-12) dayofWeek(0/7-6) commandsOrScripts

Here’s another popular way to provide a quick syntax guide using the first two lines of the cron table:

# Minute   Hour   Day of Month   Month of Year      Day of Week     Commands or Scripts
# (0-59)  (0-23)     (1-31)    (1-12 or Jan-Dec)  (0-6 or Sun-Sat)

How It Works

Interpreting a cron table entry can seem cryptic at first. The key is to understand that the first five columns specify a time and frequency, and the sixth column contains OS commands or scripts being executed.

Having said that, the cron utility has a few quirks that need further explanation. For example, the fifth column is the day of the week. Sunday is usually designated by a 0 (with some OSs, Sunday can also be designated by a 7); Monday by a 1; Tuesday by a 2; and so on, to Saturday, which is indicated with a 6.

There also appear to be overlapping columns, such as the third column (day of the month) and the fifth column (day of the week). These columns allow you to create flexible schedules for jobs that have to run on schedules such as the 1st and 15th day of the month, or on a certain day of the week. Put an asterisk in the column that you’re not using. For example, to run a backup job on the 1st and 15th (at 4:00 a.m.), do so as follows:

0 4 1,15 * * /home/oracle/bin/rmanback.bsh

Or if you need a job to run on every Tuesday (at 4:00 a.m.), do so as follows:

0 4 * * 2 /home/oracle/bin/rmanback.bsh

If you have to run a job on the 1st and 15th and every Tuesday, fill in both columns:

0 4 1,15 * 2 /home/oracle/bin/rmanback.bsh

Running a Job Every Minute

Suppose that you want a job to check once per minute to see whether a database server is available. You can do so by putting the following in your cron table (you have to modify the IP address for your server):

* * * * * ping 11.214.402.51

A * in every column instructs cron to run the command once per minute. If the ping command is successful, nothing happens. If an error is thrown by a command run from cron, cron will by default send an email to the email account of the OS owner of the cron table (see recipe 10-6 for details on how to modify locations where email is sent). This is a simple but effective method for monitoring the availability of a database server.

Running a Job Every N Seconds

The cron utility can be scheduled to run with a granularity as small as minutes. Although you can’t schedule a cron at the granularity of seconds, it is possible to creatively run a script from cron every N many seconds. For example, suppose that you want to run a script every 30 seconds from cron. You can simulate it as follows:

* * * * * /home/oracle/bin/commands.sh
* * * * *  sleep 30; /home/oracle/bin/commands.sh

In this manner, you can enable commands or jobs that have to run more frequently than 1 minute. It is probably a rare requirement, but sometimes necessary.

Using Keywords to Run Jobs

Note that on some of the modern versions of cron, you can specify keywords to indicate a time and frequency for a job to start. For example, the following instructs cron to run a job daily at midnight:

@daily /home/oracle/bin/rmanback.bsh

Table 10-2 shows the mapping of frequency keywords to the standard syntax.

Table 10-2. Frequency Keyword and Equivalent Standard Syntax

Keyword

Standard Syntax

Translation

hourly

0 * * * *

Run at the top of every hour

daily

0 0 * * *

Run daily at midnight

weekly

0 0 * * 0

Run weekly first day of week at midnight

monthly

0 0 1 * *

Run monthly on the first day of month at midnight

yearly

0 0 1 1 *

Run yearly on first month of the year at midnight

reboot

Execute when system reboots

 

midnight

Same as daily

 

annually

Same as yearly

 

Specifying a keyword is syntactically easier, but has less flexibility as to what minute, hour, or day the job will execute. Keep in mind that you probably won’t have several cron jobs to execute at the same time (overloading the system), so don’t overuse keywords such as hourly and daily.

USING THE AT SCHEDULER

You can use the at command to schedule a job to run once at a specified point in the future. Here’s an example:

$ echo "’go home’ | mailx -s ’time to go’ [email protected]"  | at 23:00

The prior command schedules an at job to send an email at 23:00 (11:00 p.m.), reminding the DBA that it is time to go home. You can use the atq (at queue) command to verify that the job is scheduled:

$ atq
111     2015-06-14 23:00 a oracle

If you want to remove the job, use the -r option:

$ at -r 111

In this manner, the at scheduler is a simple but effective way to create a scheduled job.

10-4. Setting Operating System Variables

Problem

You have this simple shell script that contains a SQL*Plus command:

#!/bin/bash
sqlplus -s <<EOF
system/manager
select username from dba_users;
EOF

You notice that a script executes well when you run it manually from the command line:

$ sqltest.bsh
USERNAME
--------------------
SYS
SYSTEM
...

However, when the script runs from cron, it throws errors reporting that commands can’t be found:

sqlplus: command not found

You want to determine the cause of the issue and ensure that the script runs successfully from cron.

Solution

When cron executes a script, it doesn’t run the OS user’s startup or login files (such as .bashrc or .bash_profile), so the variables set in the startup scripts aren’t available when cron executes. When a shell script running from cron can’t find a command, it usually means that a required directory path has not been defined. Therefore, any script executed from cron has to explicitly set any required variables such as ORACLE_HOME, ORACLE_SID, and PATH. In this situation, one solution is to set any required variables directly within the shell script. Here’s an example:

#/bin/bash
export ORACLE_HOME=/u01/app/oracle/product/12.1.0.2/db_1
export ORACLE_SID=O1212
export PATH=$PATH:$ORACLE_HOME/bin
#
sqlplus -s <<EOF
system/foo
select username from dba_users;
EOF

In this way, the shell script has the required variables available when it executes from cron.

How It Works

When running a shell script from cron, you should explicitly define any variables the shell script requires. Don’t rely on startup scripts because they will not get executed.

The solution section showed how to directly place the variables within the shell script. In many scenarios, however, DBAs prefer to keep a separate script that contains required variable definitions and execute them from any other shell scripts that require the variables to be set.

An example will demonstrate this. Suppose that you have two shell scripts. The first one, .bash_profile, contains commands to set OS variables:

export ORACLE_HOME=/u01/app/oracle/product/12.1.0.2/db_1
export ORACLE_SID=O1212
export PATH=$PATH:$ORACLE_HOME/bin

And suppose you also have a shell script named sqltest.bsh that contains the following code:

#!/bin/bash
sqlplus -s <<EOF
system/manager
select username from dba_users;
EOF

You can instruct cron to first run the script to set the oracle user’s environment variables and then run the script containing database commands. You specify multiple scripts separated by a semicolon. Here’s an example:

0 4 * * * . /home/oracle/.bash_profile; /home/oracle/bin/sqltest.bsh

Notice that the first script is run with the dot notation to source the environment variables so that the variables are visible to any subsequent scripts or commands that are executed.

10-5. Specifying the Execution Shell

Problem

Suppose that the following script is running from cron:

export ORACLE_HOME=/u01/app/oracle/product/12.1.0.2/db_1
export ORACLE_SID=O1212
export PATH=$PATH:$ORACLE_HOME/bin
#
sqlplus -s <<EOF
system/foo
select username from dba_users;
EOF

When a cron job executes, the script is throwing an error, saying it can’t find the export command:

export: Command not found.

You want to determine why this standard Bash shell command (export, in this case) isn’t functioning properly.

Solution

A script is run from cron, it will run the script using the default shell defined for a user. Therefore, if your default shell is defined to be the C shell the OS will execute any commands/scripts running from cron using the C shell (unless otherwise noted), so commands unique to the Bash shell will not be interpreted correctly. For example, suppose that the default shell is the C shell; an error is returned when the following Bash shell export command runs because the C shell doesn’t have an export command:

export ORACLE_SID=O1212
export: Command not found.

To work around this, ensure that all scripts specify in the first line which shell should be used to interpret the commands. Here’s an example:

#!/bin/bash

Another method to ensure that the correct shell is used is to specify the shell to execute the script. For example, the following cron entry instructs cron to execute the script using the Bash shell:

0 4 * * * /bin/bash /home/oracle/bin/sqltest.bsh

On Linux systems, you can also use the cron SHELL variable to instruct cron to run commands within the cron table using a specific shell:

SHELL=/bin/bash
0 4 * * * /home/oracle/bin/sqltest.bsh

How It Works

The solution section outlined three techniques to ensure that the correct shell is used when commands or scripts are executed. Any of these methods is fine, and DBAs use all three. The technique used usually boils down to a personal preference or a standard that a group has adopted.

10-6. Redirecting cron Output

Problem

You’re trying to troubleshoot issues with a cron job and want to ensure that you have a log file that captures the output when cron executes.

Solution

You can specify that any output generated by a cron entry be redirected to a file. This example writes standard output to a file named rmanback.log (for this example to work, the /home/oracle/bin/log directory must exist):

0 0 * * * /home/oracle/bin/rmanback.bsh >/home/oracle/bin/log/rmanback.log

Keep in mind that > is synonymous with 1>, so the following line is equivalent to the prior line:

0 0 * * * /home/oracle/bin/rmanback.bsh 1>/home/oracle/bin/log/rmanback.log

If you want standard error to be redirected to the same place as standard output, do so as follows:

0 0 * * * /home/oracle/bin/rmanback.bsh 1>/home/oracle/bin/log/rmanback.log 2>&1

In the previous line, 1> redirects standard output, and 2>&1 specifies that the standard error should go to the same location in which the standard output is located (refer to recipe 2-9 for more details on redirecting output).

If the log file already exists, > instructs the OS to overwrite the file and create a new file. If you want to append to an existing log file, use the >> syntax:

0 0 * * * /home/oracle/bin/backup.bsh 1>>/home/oracle/bin/log/bck.log 2>&1

This code appends any relevant messages (both regular and error messages) to the existing log file. Sometimes you’ll want to append if you have to capture the output from multiple runs of a job. For example, it is hard to troubleshoot something that happened a few days ago if you have a daily job that overwrites the existing log file.

How It Works

In most scenarios, you should save the output of your cron job in a log file, which provides a troubleshooting mechanism when there are issues. In addition to capturing the cron job output in a file, you can have the output emailed to you (a unique file name for the log file might be required). These topics are discussed next.

Mailing Output

If you don’t redirect the output for a cron job, any output from the job will be emailed to the user who owns the cron job. On Linux systems, you can override it by specifying the MAILTO variable directly within the cron table. Here’s an example:

MAILTO=[email protected]
0 0 * * * /home/oracle/bin/rmanback.bsh

If you don’t want the output to go anywhere, redirect output to the proverbial bit bucket. The following entry sends the standard output and standard error to the /dev/null device:

0 0 * * * /home/oracle/bin/rmanback.bsh 1>/dev/null 2>&1

Solaris systems do not support the MAILTO feature. To work around it, pipe the cron job to an email address as follows:

0 0 * * * /home/oracle/bin/rmanback.bsh | mail -s "backup" [email protected]

Generating Unique Log File Names

If you have to generate a unique name for the log file each time it runs, use the date command. The following generates a unique daily log file name:

0 0 * * * /home/oracle/bin/rmanback.bsh
1>/home/oracle/bin/log/rmanback.$(/bin/date +\%Y\%m\%d).log

Image Note  The two preceding lines of code were on one line in the cron table, but didn’t fit on this page. The line was broken into two lines (but should be just one line in the cron table). There is no way to split a single cron command line onto multiple lines with the backslash () character (as you can do when operating in the shell).

The percent (%) character is escaped with the backslash () character. The % character has to be escaped; otherwise, cron will interpret % as a newline character, and all code after the first % will be sent to the command as standard input.

You can creatively modify the date command per your requirements. For example, if you want to keep only the last 7 days of log files, specify the date command to return only the day of the week (not the year, month, or day):

0 0 * * * /home/oracle/bin/rmanback.bsh 1>/home/oracle/bin/log/rmanback.$(/bin/date +\%u).log

The date +%u command will return an integer 0 through 6, depending on the day of the week. After 7 days, you’ll end up with 7 log files: rmanback.0.log through rmanback.6.log. As each new week rolls around, the old log files will be overwritten.

ATTACHING FILES TO AN EMAIL

If you’re working with a log file or binary file that you want sent as an attachment (not as the message body), use the uuencode command or the mutt utility to accomplish this task. The basic syntax for uuencode is as follows:

uuencode [INFILE] REMOTEFILE

For example, to attach a file named prodAWR.html to an email, do so as follows:

$ uuencode prodAWR.html prodAWR.html | mail -s "prod AWR report" [email protected]

You may be thinking that you could just send the email like this:

$ mail -s "prod AWR report" [email protected] <prodAWR.html

You can do so if the output contains only ASCII text. If the file isn’t an ASCII file, however, the output will not be interpreted as an attachment and will arrive as indecipherable text. In this situation, you must attach the file to the email so that it won’t be interpreted as the message body.

If available, you can also use the mutt utility to attach files to email. Here’s an example:

$ echo "AWR rpt" | mutt -a "/home/oracle/prodAWR.html" -s "AWR rpt" --[email protected]

In this way, you can attach files (log files, binary files, backup files, and so on) to an email.

10-7. Embedding Conditional Logic

Problem

You want to automate a job that checks for a condition.

Solution

The solution is to realize that you can use standard Bash shell operators directly from within cron. For example, to test whether the output from the ps command returned a value, use the && or || operators (refer to Chapter 7 for details on conditional operators).

Here’s a sample cron entry that will check once per hour for a background process (smon in this situation); if the background process isn’t running, an email is sent:

01 * * * * ps -ef | grep smon>/dev/null || echo "problem" | mailx -s "issue" [email protected]

In the preceding line of code, the || operator is interpreted this way: “If the command to the left of the || operator is not successful (ps does not return a value), run the code to the right of the || operator.”

Suppose that you want an automated job to run once per hour to check for the existence of an error file, and to send an email if it exists. You can do so as follows:

01 * * * * [ -f /home/oracle/err.txt ] && mailx -s "exists" [email protected] </home/oracle/err.txt

In the prior line of code, the && is interpreted as follows: “If the command to the left of the && operator is successful (the file exists), run the code to the right of the && operator.”

DBAs and SAs use test instead of [ ] to accomplish the same task. The following line of code is equivalent to the prior line of code:

01 * * * * test -f /home/oracle/err.txt && mailx -s "exists" [email protected] </home/oracle/err.txt

In this manner, you can automate tasks depending on a condition existing (or not).

How It Works

Once you understand that you can use standard Bash shell features directly from within cron, you can creatively schedule jobs as required in your environment. To that point, it’s worth repeating this example from Chapter 7:

33 * * * * ps -ef | grep dbwatch | grep -v grep || nohup /home/oracle/bin/dbwatch.bsh &

The prior line of code checks for the existence of a process; if it isn’t present, the job is restarted in the background.

You can separate commands within cron by using a semicolon, and you can also execute code in a subshell by enclosing it in parentheses. For example, at 2 minutes after the top of the hour, execute the following:

02 * * * * cd /home/oracle/err ; (tail -100 err.txt) | grep ORA-00600 && echo "found error"

Image Caution  Don’t embed overly complex logic into a cron table; it makes the logic hard to understand and results in less-maintainable code. If you find the logic is getting complicated, put the code into a shell script and execute the script instead.

Table 10-3 summarizes special shell features that are often used to embed logic into cron jobs.

Table 10-3. Shell Operators and Meanings

Operator

Meaning

&

Run the command in the background.

;

Run the command to the left of ; and run the command to the right of ; (e.g., separate the two commands).

&&

If command to the left of && is successful, run the command to the right of &&.

||

If the command to the left of || fails, run the command to the right of ||.

()

Execute the command within the parentheses in a subshell.

[ ]

Test a condition (can also use the test command).

10-8. Troubleshooting cron

Problem

Your cron job doesn’t appear to be running. You want to do some troubleshooting to determine the cause of the issue.

Solution

If you have a cron job that isn’t running correctly, follow these steps to troubleshoot the issue:

  1. Copy your cron entry, paste it to the OS command line, and manually run the command. A small typo in a directory or file name can often be the source of the problem. Manually running the command highlights errors like these.
  2. If the script runs Oracle utilities, ensure that you source (set) the required OS variables within the script (such as ORACLE_HOME, ORACLE_SID, and PATH). These variables are often set by startup scripts (such as HOME/.bashrc) when you log on. Because cron doesn’t run a user’s startup scripts, any required variables must be set explicitly within the script.
  3. Ensure that the first line of any shell scripts invoked from cron specifies the name of the program that will be used to interpret the commands within the script. For example, #!/bin/bash should be the first entry in a Bash shell script. Because cron doesn’t run a user’s startup scripts (such as HOME/.bashrc), you can’t assume that your OS user’s default shell will be used to run a command or script evoked from cron.
  4. If you execute a script, check the permissions on the script file and ensure that it is set to executable for the user running the script.
  5. Ensure that the cron background process or service is running.
  6. Check your email on the server. The cron utility will usually send an email to the OS account when there are issues with a misbehaving cron job.
  7. Inspect the contents of the /var/log/cron file for any errors. Sometimes this file has relevant information regarding a cron job that has failed to run.

We’ve found that any issues with cron are usually related to one of the previously listed items. The prior list is a good place to start when experiencing chronic issues.

How It Works

Troubleshooting cron is necessary when the job doesn’t execute as expected, which often can be due to environment variables not being set. If you want to explicitly view the environment settings as cron is using them, put this line in your cron table:

* * * * * env > /tmp/env.txt

After the command executes and populates the env.txt file, remove the line from the cron table. The env.txt file will show the environment variables and values that cron is using. In this manner, you can quickly determine what cron is using for variables such as PATH and HOME; they may not be what you were expecting. Therefore, it is always better to explicitly set any required variables.

Additionally, cron will execute commands using the default shell of the OS user that owns the cron table. This means if your default shell is the C shell, any commands exclusive to the Bash shell will not be correctly interpreted when running a cron job. As a best practice, explicitly instruct cron which shell to use when executing commands and scripts.

If you suspect that something is wrong with the cron service or background daemon, you can verify that it is working via the wall (write all users) command by adding this entry to your cron table:

* * * * * wall "cron is working"

If all is well, all users logged on to the server will see a message at the top of the minute, indicating that cron is working. Because all users logged on to the server will see the message, remember to remove this cron entry as soon as you’re done testing. If you don’t want to send the message to all users, use the write command with a specified terminal (use the who command to list logged-in users and terminal information).

ORACLE SCHEDULER VERSUS CRON

Oracle Scheduler is a tool that provides a way to automate job scheduling. Implemented via the DBMS_SCHEDULER internal PL/SQL package, Oracle Scheduler offers a sophisticated set of features for scheduling jobs. There are currently more than 70 procedures and functions available within the DBMS_SCHEDULER package.

You may be wondering whether to use Oracle Scheduler or the Linux/Solaris cron utility for scheduling and automating tasks. Here are some of the benefits that Oracle Scheduler has over cron:

  • Makes the execution of a job dependent on the completion of another job
  • Robust resource balancing and flexible scheduling features
  • Runs jobs based on an event (such as the completion of another job)
  • DBMS_SCHEDULER PL/SQL package syntax works the same, regardless of the OS
  • Runs status reports using the data dictionary
  • In a clustered environment, no need to worry about synchronizing multiple cron tables for each node in the cluster
  • Is implemented, maintained, and monitored via Enterprise Manager

Regardless of Oracle Scheduler’s benefits, many DBAs prefer to use a scheduling utility such as cron. Here are some of the advantages of cron:

  • Easy to use; simple, tried and true; takes only seconds to create or modify jobs
  • Almost universally available on all Linux/Solaris boxes; for the most part, runs nearly identically, regardless of the Linux/Solaris platform (yes, there are minor differences)
  • Database agnostic; operates independently of the database and works the same way regardless of the database vendor or version
  • Works even when the database is not available

These lists aren’t comprehensive, but they give you an idea of the uses of each scheduling tool. If you require something more sophisticated than cron, consider using Oracle Scheduler. Note that cron and Oracle Scheduler aren’t mutually exclusive; for a given task, use whichever tool meets your requirements.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset