文章目录
之前是使用 crontab 去调度程序,让程序启动,但是在实际中很少只是使用 crontab 去调度。一般都是 crontab 和自身调度结合使用去调度程序,所以现在将 psurfdata.cpp (数据入库程序)调整为自身调度。
程序自身调度其实就是利用 while(true) 让程序一直执行,执行一遍之后就 sleep() 一段指定的时间。这就有点类似于 crontab 任务中的指定时间去执行程序。
一 、优化程序,修改存在的问题
(1)这个程序现在是打开了数据文件存放的目录,就马上连接数据库。其实这是有些不妥的。如果目录中没有数据文件,其实是不需要连接数据库的,因为没有文件要处理。这样就会浪费数据库连接资源
if ( Dir.OpenDir(argv[1],"SURF_ZH_*.txt",10,false,true) == false )
{
logfile.Write("Dir.OpenDir(%s) failed.\n",argv[1]);
return -1;
}
logfile.Write("Dir.OpenDir(%s) Sucess.\n",argv[1]);
// 导入数据库前,连接数据库
if ( conn.connecttodb("scott/123456@snorcl11g_198","Simplified Chinese_China.ZHS16GBK") != 0 )
{
logfile.Write("connect database failed.\n%s\n",conn.m_cda.message); return -1;
}
while (true)
{
// (1) 先读取文件,其实这里读取文件是放在容器中的,
// 只是封装了ReadDir() ,容器声明在 ReadDir() 里面
if ( Dir.ReadDir() == false )
{
logfile.Write("Dir.ReadDir() 读取文件完毕.\n");
break;
}
//(2) 开始处理文件
logfile.Write("开始处理文件 filename=%s\n",Dir.m_FullFileName);
if ( _psurfdata() == false )
{
logfile.Write("失败。\n");
break;
}
logfile.Write("处理文件结束 filename=%s\n",Dir.m_FullFileName);
}
return 0;
}
(2)那应该什么时候开始连接数据库比较合理?在扫描了目录( ReadDir() )确认有需要处理的数据文件之后开始连接数据库。所以需要将连接数据库的代码的位置调整到扫描目录之后。
while (true)
{
// (1) 先读取文件,其实这里读取文件是放在容器中的,
// 只是封装了ReadDir() ,容器声明在 ReadDir() 里面
if ( Dir.ReadDir() == false )
{
logfile.Write("Dir.ReadDir() 读取文件完毕.\n");
break;
}
// 连接数据库
if ( conn.m_state == 0 )
{
if ( conn.connecttodb("scott/123456@snorcl11g_198","Simplified Chinese_China.ZHS16GBK") != 0 )
{
logfile.Write("connect database failed.\n%s\n",conn.m_cda.message); break;
}
}
二、修改程序,让程序调度自身
到现在为止,已经做到将分钟气象观测数据导入数据库。在做这个项目的开始,就有一个要求就是能够尽可能地模拟出真实的气象数据中心。
其中就有一个要求就是能够实时地处理数据,也就是说气象站点生成了气象观测数据了,能够及时地将数据取回来,然后将数据处理好导入数据库。这三个步骤应该是能自动完成的,一气呵成的。这样就能更接近一步真实的气象项目。
为了能够达到这个要求,就需要将程序修改成程序能够自身调度,当然也可以使用 crontab 任务去调度,但是实际中并不只是使用 crontab 任务去调度。
1.修改模拟气象站点生成气象观测数据
(1)气象站点的气象观测数据是隔一段时间就会生成的,所以我们也要实现这个。现在使用的是分钟气象观测数据,所以要求每隔 60 秒就生成一批气象观测数据。
在前言已经说了,自身调度就是使用 while(true),让程序一直执行,分钟气象观测数据,就是执行一次循环就 sleep(60);
(2)让程序一直调度自身还有一个问题,就是程序出错了还能够继续运行下去。但是要注意的是程序出的错误,不是所有的错误都能忽略掉,让程序继续运行的,在工程的优化的,错误处理有详细的说明。
这个程序能出的错误,并不是能数据库断开连接类的,所以能将这些错误忽略掉,当出现错误时就不继续执行这一次的操作的剩下步骤,continue 执行下一次操作,但是不 return 让程序停止。
下图是将气象站点参数加载到程序容器中时可能数据的格式不对,会出错。
修改的模拟气象站点生成气象观测数据程序(crtsurfdata.cpp)如下:
while( true )
{
// 二、将气象站点参数加载程序中的容器
if ( LoadSTCode(argv[1]) == false )
{
logfile.Write("LoadSTCode(%s)failed.\n",argv[1]);
sleep(60);
continue;
}
logfile.Write("气象站点参数加载成功(%s)\n",argv[1]);
// 三、模拟生成观测数据
CrtSurfData();
// 四、将观测数据写入指定的文件
if ( CrtSurfFile(argv[2]) == false )
{
logfile.Write("CrtSurfFile(%s)failed.\n",argv[2]);
sleep(60);
continue;
}
sleep(60);
}
return 0;
}
2.修改 ftpgetfile.cpp
当模拟的数据源生成了气象观测数据,要及时地将数据取回来,修改 ftpgetfile.cpp 的方法思路与修改前面的程序是大同小异的。
(1)将主要的步骤,必要的步骤放到 while(true) 中,指定 sleep() 的时间
(2)忽略掉出现的错误,将 return 改为 continue。
3.修改处理入库程序(psurfdata.cpp)
处理思路大同小异
while ( true )
{
logfile.Write("开始扫描目录。\n");
if ( Dir.OpenDir(argv[1],"SURF_ZH_*.txt",10,false,true) == false )
{
logfile.Write("Dir.OpenDir(%s) failed.\n",argv[1]);
sleep( atoi( argv[3] ) );
continue;
}
logfile.Write("Dir.OpenDir(%s) Sucess.\n",argv[1]);
// 4.2 逐个处理目录中的数据文件,并将处理好的数据导入数据库
while (true)
{
// (1) 先读取文件,其实这里读取文件是放在容器中的,
// 只是封装了ReadDir() ,容器声明在 ReadDir() 里面
if ( Dir.ReadDir() == false )
{
logfile.Write("Dir.ReadDir() 读取文件完毕.\n");
break;
}
// 连接数据库
if ( conn.m_state == 0 )
{
if ( conn.connecttodb("scott/123456@snorcl11g_198","Simplified Chinese_China.ZHS16GBK") != 0 )
{
{
logfile.Write("connect database failed.\n%s\n",conn.m_cda.message); break;
}
}
logfile.Write("连接数据库成功.\n");
//(2) 开始处理文件
logfile.Write("开始处理文件 filename=%s\n",Dir.m_FullFileName);
if ( _psurfdata() == false )
{
logfile.Write("失败。\n");
break;
}
logfile.Write("处理文件结束 filename=%s\n",Dir.m_FullFileName);
}
// 处理完一批数据就断开与数据库的连接
if ( conn.m_state == 1 )
{
conn.disconnect();
logfile.Write("断开数据库连接。\n");
}
sleep( atoi( argv[3] ) );
}
return 0;
}
三、利用脚本启动关闭程序
修改好了程序之后,就可以启动这三个程序了,但是每次都要手动去敲每个程序的执行程序,并把执行参数写上,这样就很麻烦。关闭程序大同小异
可以写两个脚本来解决上述的问题,一个脚本用来启动这些程序,一个用来停止运行。
1.启动脚本
启动程序,让程序在后台运行,加上 “&” 符合
# 该脚本用于启动气象数据中心的服务程序
# 生成全国气象站点分钟气象观测数据文件
/htidc/qxidc/bin/crtsurfdata /htidc/qxidc/ini/stcode.ini /data/qxidc/ftp/surfdata /log/qxidc/crtsurfdata.log &
# 采集分钟气象观测数据文件
/htidc/public/bin/ftpgetfile /log/qxidc/ftpgetfile_surfdata.log "<host>8.131.80.81:21</host><mode>1</mode><username>root</username><password>ue68malinux</password><localpath>/data/qxidc/surfdata</localpath><remotepath>/data/qxidc/ftp/surfdata</remotepath><matchname>SURF_*.TXT</matchname><ptype>2</ptype><remotepathbak>/data/qxidc/ftp/surfdatabak</remotepathbak><listfilename>/htidc/qxidc/list/ftpgetfile_surfdata.list</listfilename><okfilename>/htidc/qxidc/list/ftpgetfile_surfdata.xml</okfilename><timetvl>30</timetvl>" &
# 处理分钟气象观测数据文件并入库
/htidc/qxidc/bin/Testpsurfdata /data/qxidc/surfdata /log/qxidc/psurfdata.log 10 &
2.关闭程序脚本
killall ftpgetfile crtsurfdata Testpsurfdata
3.给予脚本可执行权限
四、总结
1.如何让程序自身调度?
(1)while(true) + sleep()
(2)忽略错误,continue
2.善于利用脚本去解决一些事情