1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
agent.php
См. документацию.
1<?php
2
9
11
12Loc::loadMessages(__FILE__);
13
14class CAllAgent
15{
16 protected const LOCK_TIME = 600;
17
18 public static function AddAgent(
19 $name, // PHP function name
20 $module = "", // module
21 $period = "N", // check for agent execution count in period of time
22 $interval = 86400, // time interval between execution
23 $datecheck = "", // first check for execution time
24 $active = "Y", // is the agent active or not
25 $next_exec = "", // first execution time
26 $sort = 100, // order
27 $user_id = false, // user
28 $existError = true // return error, if agent already exist
29 )
30 {
31 global $DB, $APPLICATION;
32
33 $z = $DB->Query("
34 SELECT ID
35 FROM b_agent
36 WHERE NAME = '".$DB->ForSql($name)."'
37 AND USER_ID".($user_id? " = ".(int)$user_id: " IS NULL")
38 );
39 if (!($agent = $z->Fetch()))
40 {
42 "MODULE_ID" => $module,
43 "SORT" => $sort,
44 "NAME" => $name,
45 "ACTIVE" => $active,
46 "AGENT_INTERVAL" => $interval,
47 "IS_PERIOD" => $period,
48 "USER_ID" => $user_id,
49 );
50 $next_exec = (string)$next_exec;
51 if ($next_exec != '')
52 $arFields["NEXT_EXEC"] = $next_exec;
53
54 $ID = CAgent::Add($arFields);
55 return $ID;
56 }
57 else
58 {
59 if (!$existError)
60 return $agent['ID'];
61
62 if ($APPLICATION instanceof CMain)
63 {
64 $e = new CAdminException(array(
65 array(
66 "id" => "agent_exist",
67 "text" => ($user_id
68 ? Loc::getMessage("MAIN_AGENT_ERROR_EXIST_FOR_USER", array('#AGENT#' => $name, '#USER_ID#' => $user_id))
69 : Loc::getMessage("MAIN_AGENT_ERROR_EXIST_EXT", array('#AGENT#' => $name))
70 )
71 )
72 ));
73 $APPLICATION->throwException($e);
74 }
75 return false;
76 }
77 }
78
79 public static function Add($arFields)
80 {
81 global $DB, $CACHE_MANAGER;
82
83 if (CAgent::CheckFields($arFields))
84 {
85 if (!is_set($arFields, "NEXT_EXEC"))
86 $arFields["~NEXT_EXEC"] = $DB->GetNowDate();
87
88 if (CACHED_b_agent !== false)
89 $CACHE_MANAGER->CleanDir("agents");
90
91 $ID = $DB->Add("b_agent", $arFields);
92 foreach (GetModuleEvents("main", "OnAfterAgentAdd", true) as $arEvent)
95 ));
96
97 return $ID;
98 }
99 return false;
100 }
101
102 public static function RemoveAgent($name, $module = "", $user_id = false)
103 {
104 global $DB;
105
106 if (trim($module) == '')
107 $module = "AND (MODULE_ID is null or ".$DB->Length("MODULE_ID")." = 0)";
108 else
109 $module = "AND MODULE_ID = '".$DB->ForSql($module, 50)."'";
110
111 $strSql = "
112 DELETE FROM b_agent
113 WHERE NAME = '".$DB->ForSql($name)."'
114 ".$module."
115 AND USER_ID".($user_id ? " = ".(int)$user_id : " IS NULL");
116
117 $DB->Query($strSql);
118 }
119
120 public static function Delete($id)
121 {
122 global $DB;
123 $id = intval($id);
124
125 if ($id <= 0)
126 return false;
127
128 $DB->Query("DELETE FROM b_agent WHERE ID = ".$id);
129
130 return true;
131 }
132
133 public static function RemoveModuleAgents($module)
134 {
135 global $DB;
136
137 if ($module <> '')
138 {
139 $strSql = "DELETE FROM b_agent WHERE MODULE_ID='".$DB->ForSql($module,255)."'";
140 $DB->Query($strSql);
141 }
142 }
143
144 public static function Update($ID, $arFields)
145 {
146 global $DB, $CACHE_MANAGER;
147 $ign_name = false;
148
149 $ID = intval($ID);
150
151 if(is_set($arFields, "ACTIVE") && $arFields["ACTIVE"]!="Y")
152 $arFields["ACTIVE"]="N";
153 if(is_set($arFields, "IS_PERIOD") && $arFields["IS_PERIOD"]!="Y")
154 $arFields["IS_PERIOD"]="N";
155 if(!is_set($arFields, "NAME"))
156 $ign_name = true;
157
158 if(CAgent::CheckFields($arFields, $ign_name))
159 {
160 if(CACHED_b_agent !== false)
161 $CACHE_MANAGER->CleanDir("agents");
162
163 $strUpdate = $DB->PrepareUpdate("b_agent", $arFields);
164 $strSql = "UPDATE b_agent SET ".$strUpdate." WHERE ID=".$ID;
165 $res = $DB->Query($strSql);
166 return $res;
167 }
168
169 return false;
170 }
171
172 public static function GetById($ID)
173 {
174 return CAgent::GetList(Array(), Array("ID"=>intval($ID)));
175 }
176
177 public static function GetList($arOrder = Array("ID" => "DESC"), $arFilter = array())
178 {
179 global $DB;
180
181 $arSqlSearch = array();
182 $arSqlOrder = array();
183
184 $arOFields = array(
185 "ID" => "A.ID",
186 "ACTIVE" => "A.ACTIVE",
187 "IS_PERIOD" => "A.IS_PERIOD",
188 "NAME" => "A.NAME",
189 "MODULE_ID" => "A.MODULE_ID",
190 "USER_ID" => "A.USER_ID",
191 "LAST_EXEC" => "A.LAST_EXEC",
192 "AGENT_INTERVAL" => "A.AGENT_INTERVAL",
193 "NEXT_EXEC" => "A.NEXT_EXEC",
194 "DATE_CHECK" => "A.DATE_CHECK",
195 "SORT" => "A.SORT"
196 );
197
198 if (!is_array($arFilter))
199 {
200 $arFilter = [];
201 }
202 foreach ($arFilter as $key => $val)
203 {
204 if ((string)$val == '')
205 {
206 continue;
207 }
208
209 switch(strtoupper($key))
210 {
211 case "ID":
212 $arSqlSearch[] = "A.ID=".(int)$val;
213 break;
214 case "ACTIVE":
215 $t_val = mb_strtoupper($val);
216 if($t_val == "Y" || $t_val == "N")
217 $arSqlSearch[] = "A.ACTIVE='".$t_val."'";
218 break;
219 case "IS_PERIOD":
220 $t_val = mb_strtoupper($val);
221 if($t_val=="Y" || $t_val=="N")
222 $arSqlSearch[] = "A.IS_PERIOD='".$t_val."'";
223 break;
224 case "NAME":
225 $arSqlSearch[] = "A.NAME LIKE '".$DB->ForSQLLike($val)."'";
226 break;
227 case "=NAME":
228 $arSqlSearch[] = "A.NAME = '".$DB->ForSQL($val)."'";
229 break;
230 case "MODULE_ID":
231 $arSqlSearch[] = "A.MODULE_ID = '".$DB->ForSQL($val)."'";
232 break;
233 case "USER_ID":
234 $arSqlSearch[] = "A.USER_ID ".(intval($val)<=0?"IS NULL":"=".intval($val));
235 break;
236 case "LAST_EXEC":
237 $arr = ParseDateTime($val, CLang::GetDateFormat());
238 if($arr)
239 {
240 $date2 = mktime(0, 0, 0, $arr["MM"], $arr["DD"]+1, $arr["YYYY"]);
241 $arSqlSearch[] = "A.LAST_EXEC>=".$DB->CharToDateFunction($DB->ForSql($val), "SHORT")." AND A.LAST_EXEC<".$DB->CharToDateFunction(ConvertTimeStamp($date2), "SHORT");
242 }
243 break;
244 case "NEXT_EXEC":
246 if($arr)
247 {
248 $date2 = mktime(0, 0, 0, $arr["MM"], $arr["DD"]+1, $arr["YYYY"]);
249 $arSqlSearch[] = "A.NEXT_EXEC>=".$DB->CharToDateFunction($DB->ForSql($val), "SHORT")." AND A.NEXT_EXEC<".$DB->CharToDateFunction(ConvertTimeStamp($date2), "SHORT");
250 }
251 break;
252 }
253 }
254
255 foreach($arOrder as $by => $order)
256 {
257 $by = mb_strtoupper($by);
258 $order = mb_strtoupper($order);
259 if (isset($arOFields[$by]))
260 {
261 if ($order != "ASC")
262 {
263 $order = "DESC";
264 }
265 $arSqlOrder[] = $arOFields[$by]." ".$order;
266 }
267 }
268
269 $strSql = "SELECT A.ID, A.MODULE_ID, A.USER_ID, B.LOGIN, B.NAME as USER_NAME, B.LAST_NAME, A.SORT, ".
270 "A.NAME, A.ACTIVE, A.RUNNING, ".
271 $DB->DateToCharFunction("A.LAST_EXEC")." as LAST_EXEC, ".
272 $DB->DateToCharFunction("A.NEXT_EXEC")." as NEXT_EXEC, ".
273 $DB->DateToCharFunction("A.DATE_CHECK")." as DATE_CHECK, ".
274 "A.AGENT_INTERVAL, A.IS_PERIOD, A.RETRY_COUNT ".
275 "FROM b_agent A LEFT JOIN b_user B ON(A.USER_ID = B.ID)";
276 $strSql .= !empty($arSqlSearch) ? " WHERE ".implode(" AND ", $arSqlSearch) : "";
277 $strSql .= !empty($arSqlOrder) ? " ORDER BY ".implode(", ", $arSqlOrder) : "";
278
279 $res = $DB->Query($strSql);
280
281 return $res;
282 }
283
284 public static function CheckFields($arFields, $ign_name = false)
285 {
286 global $DB, $APPLICATION;
287
288 $errMsg = array();
289
290 if(!$ign_name && (!is_set($arFields, "NAME") || mb_strlen(trim($arFields["NAME"])) <= 2))
291 $errMsg[] = array("id" => "NAME", "text" => Loc::getMessage("MAIN_AGENT_ERROR_NAME"));
292
293 if(
294 array_key_exists("NEXT_EXEC", $arFields)
295 && (
296 $arFields["NEXT_EXEC"] == ""
297 || !$DB->IsDate($arFields["NEXT_EXEC"], false, false, "FULL")
298 )
299 )
300 {
301 $errMsg[] = array("id" => "NEXT_EXEC", "text" => Loc::getMessage("MAIN_AGENT_ERROR_NEXT_EXEC"));
302 }
303
304 if(
305 array_key_exists("DATE_CHECK", $arFields)
306 && $arFields["DATE_CHECK"] <> ""
307 && !$DB->IsDate($arFields["DATE_CHECK"], false, false, "FULL")
308 )
309 {
310 $errMsg[] = array("id" => "DATE_CHECK", "text" => Loc::getMessage("MAIN_AGENT_ERROR_DATE_CHECK"));
311 }
312
313 if(
314 array_key_exists("LAST_EXEC", $arFields)
315 && $arFields["LAST_EXEC"] <> ""
316 && !$DB->IsDate($arFields["LAST_EXEC"], false, false, "FULL")
317 )
318 {
319 $errMsg[] = array("id" => "LAST_EXEC", "text" => Loc::getMessage("MAIN_AGENT_ERROR_LAST_EXEC"));
320 }
321
322 if(!empty($errMsg))
323 {
324 if ($APPLICATION instanceof CMain)
325 {
326 $e = new CAdminException($errMsg);
327 $APPLICATION->ThrowException($e);
328 }
329 return false;
330 }
331 return true;
332 }
333
338 protected static function OnCron()
339 {
340 if (COption::GetOptionString('main', 'agents_use_crontab', 'N') == 'Y' || (defined('BX_CRONTAB_SUPPORT') && BX_CRONTAB_SUPPORT === true))
341 {
342 return (defined('BX_CRONTAB') && BX_CRONTAB === true);
343 }
344 return null;
345 }
346
347 public static function CheckAgents()
348 {
349 define("START_EXEC_AGENTS_1", microtime(true));
350
351 define("BX_CHECK_AGENT_START", true);
352
353 //For a while agents will execute only on primary cluster group
354 if((defined("NO_AGENT_CHECK") && NO_AGENT_CHECK===true) || (defined("BX_CLUSTER_GROUP") && BX_CLUSTER_GROUP !== 1))
355 return null;
356
357 $res = CAgent::ExecuteAgents();
358
359 define("START_EXEC_AGENTS_2", microtime(true));
360
361 return $res;
362 }
363
364 public static function ExecuteAgents()
365 {
366 global $DB, $CACHE_MANAGER, $pPERIOD, $USER;
367
368 $cron = static::OnCron();
369
370 if ($cron !== null)
371 {
372 $str_crontab = ($cron ? " AND IS_PERIOD='N' " : " AND IS_PERIOD='Y' ");
373 }
374 else
375 {
376 $str_crontab = "";
377 }
378
379 $saved_time = 0;
380 $cache_id = "agents".$str_crontab;
381 if (CACHED_b_agent !== false && $CACHE_MANAGER->Read(CACHED_b_agent, $cache_id, "agents"))
382 {
383 $saved_time = $CACHE_MANAGER->Get($cache_id);
384 if (time() < $saved_time)
385 {
386 return "";
387 }
388 }
389
390 $connection = \Bitrix\Main\Application::getConnection();
391 $helper = $connection->getSqlHelper();
392
393 $strSql = "
394 SELECT 'x'
395 FROM b_agent
396 WHERE
397 ACTIVE = 'Y'
398 AND NEXT_EXEC <= " . $helper->getCurrentDateTimeFunction() . "
399 AND (DATE_CHECK IS NULL OR DATE_CHECK <= " . $helper->getCurrentDateTimeFunction() . ")
400 ".$str_crontab."
401 LIMIT 1
402 ";
403
404 $db_result_agents = $DB->Query($strSql);
405 if ($db_result_agents->Fetch())
406 {
407 if(!$connection->lock($cache_id))
408 {
409 return "";
410 }
411 }
412 else
413 {
414 if (CACHED_b_agent !== false)
415 {
416 $rs = $DB->Query("SELECT UNIX_TIMESTAMP(NEXT_EXEC)-UNIX_TIMESTAMP(" . $helper->getCurrentDateTimeFunction() . ") DATE_DIFF FROM b_agent WHERE ACTIVE = 'Y' " . $str_crontab . " ORDER BY NEXT_EXEC LIMIT 1");
417 $ar = $rs->Fetch();
418
419 if (!$ar || $ar["DATE_DIFF"] < 0)
420 $date_diff = 0;
421 elseif ($ar["DATE_DIFF"] > CACHED_b_agent)
422 $date_diff = CACHED_b_agent;
423 else
424 $date_diff = $ar["DATE_DIFF"];
425
426 if ($saved_time > 0)
427 {
428 $CACHE_MANAGER->Clean($cache_id, "agents");
429 $CACHE_MANAGER->Read(CACHED_b_agent, $cache_id, "agents");
430 }
431 $CACHE_MANAGER->Set($cache_id, intval(time()+$date_diff));
432 }
433
434 return "";
435 }
436
437 $strSql =
438 "SELECT ID, NAME, AGENT_INTERVAL, IS_PERIOD, MODULE_ID, RETRY_COUNT ".
439 "FROM b_agent ".
440 "WHERE ACTIVE = 'Y' ".
441 " AND NEXT_EXEC <= " . $helper->getCurrentDateTimeFunction() . " ".
442 " AND (DATE_CHECK IS NULL OR DATE_CHECK <= " . $helper->getCurrentDateTimeFunction() . ") ".
443 $str_crontab.
444 " ORDER BY RUNNING ASC, SORT desc ";
445
446 // limit selection to prevent excessive UPDATE
447 $limit = ($cron ? COption::GetOptionInt("main", "agents_cron_limit", 1000) : COption::GetOptionInt("main", "agents_limit", 100));
448 if ($limit > 0)
449 {
450 $strSql .= ' LIMIT ' . $limit;
451 }
452
453 $db_result_agents = $DB->Query($strSql);
454 $ids = '';
455 $agents_array = array();
456 while ($db_result_agents_array = $db_result_agents->Fetch())
457 {
458 $agents_array[] = $db_result_agents_array;
459 $ids .= ($ids <> ''? ', ':'').$db_result_agents_array["ID"];
460 }
461 if ($ids <> '')
462 {
463 $strSql = "UPDATE b_agent SET DATE_CHECK = " . $helper->addSecondsToDateTime(self::LOCK_TIME) . " WHERE ID IN (".$ids.")";
464 $DB->Query($strSql);
465 }
466
467 $connection->unlock($cache_id);
468
470 $logFunction = (defined("BX_AGENTS_LOG_FUNCTION") && function_exists(BX_AGENTS_LOG_FUNCTION)? BX_AGENTS_LOG_FUNCTION : false);
471
472 ignore_user_abort(true);
473 $startTime = time();
474
475 foreach ($agents_array as $arAgent)
476 {
477 if (time() - $startTime > self::LOCK_TIME - 30)
478 {
479 // locking time control; 30 seconds delta is for the possibly last agent
480 break;
481 }
482
483 if ($logFunction)
484 {
485 $logFunction($arAgent, "start");
486 }
487
488 if ($arAgent["MODULE_ID"] <> '' && $arAgent["MODULE_ID"]!="main")
489 {
490 if (!CModule::IncludeModule($arAgent["MODULE_ID"]))
491 continue;
492 }
493
494 //update the agent to the running state - if it fails it'll go to the end of the list on the next try
495 $DB->Query("UPDATE b_agent SET RUNNING = 'Y', RETRY_COUNT = RETRY_COUNT+1 WHERE ID = ".$arAgent["ID"]);
496
497 //these vars can be assigned within agent code
498 $pPERIOD = $arAgent["AGENT_INTERVAL"];
499
501
502 // global $USER should not be available here
503 $USER = null;
504
505 try
506 {
507 $eval_result = "";
508 $e = eval("\$eval_result=".$arAgent["NAME"]);
509 }
510 catch (Throwable $exception)
511 {
513
514 $application = \Bitrix\Main\Application::getInstance();
515 $exceptionHandler = $application->getExceptionHandler();
516 $exceptionHandler->writeToLog(new \Bitrix\Main\SystemException("Error in agent {$arAgent["NAME"]}.", 0, '', 0, $exception));
517
518 continue;
519 }
520
522
523 if ($logFunction)
524 {
525 $logFunction($arAgent, "finish", $eval_result, $e);
526 }
527
528 if ($e === false)
529 {
530 continue;
531 }
532 elseif ($eval_result == '')
533 {
534 $strSql = "DELETE FROM b_agent WHERE ID = ".$arAgent["ID"];
535 }
536 else
537 {
538 if ($logFunction && function_exists('token_get_all'))
539 {
540 if (count(token_get_all("<?php ".$eval_result)) < 3)
541 {
542 //probably there is an error in the result
543 $logFunction($arAgent, "not_callable", $eval_result, $e);
544 }
545 }
546
547 $strSql = "
548 UPDATE b_agent SET
549 NAME = '".$DB->ForSQL($eval_result)."',
550 LAST_EXEC = " . $helper->getCurrentDateTimeFunction() . ",
551 NEXT_EXEC = " . $helper->addSecondsToDateTime($pPERIOD, $arAgent["IS_PERIOD"]=="Y"? "NEXT_EXEC" : null) . ",
552 DATE_CHECK = NULL,
553 RUNNING = 'N',
554 RETRY_COUNT = 0
555 WHERE ID = ".$arAgent["ID"];
556 }
557 $DB->Query($strSql);
558 }
559
560 return null;
561 }
562}
563
564class CAgent extends CAllAgent
565{
566}
$connection
Определения actionsdefinitions.php:38
const BX_CRONTAB
Определения bootstrap.php:12
global $APPLICATION
Определения include.php:80
static GetOptionInt($module_id, $name, $def="", $site=false)
Определения option.php:49
static Disable()
Определения time.php:31
static Enable()
Определения time.php:36
global $CACHE_MANAGER
Определения clear_component_cache.php:7
$startTime
Определения sync.php:69
$arFields
Определения dblapprove.php:5
$arr
Определения file_new.php:624
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$res
Определения filter_act.php:7
if($ajaxMode) $ID
Определения get_user.php:27
global $DB
Определения cron_frame.php:29
const NO_AGENT_CHECK
Определения cron_frame.php:17
global $USER
Определения csv_new_run.php:40
$application
Определения bitrix.php:23
$z
Определения options.php:31
ExecuteModuleEventEx($arEvent, $arParams=[])
Определения tools.php:5214
ParseDateTime($datetime, $format=false)
Определения tools.php:638
ConvertTimeStamp($timestamp=false, $type="SHORT", $site=false, $bSearchInSitesOnly=false)
Определения tools.php:733
GetModuleEvents($MODULE_ID, $MESSAGE_ID, $bReturnArray=false)
Определения tools.php:5177
is_set($a, $k=false)
Определения tools.php:2133
$name
Определения menu_edit.php:35
$order
Определения payment.php:8
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
$ar
Определения options.php:199
if(empty($signedUserToken)) $key
Определения quickway.php:257
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
$val
Определения options.php:1793
$rs
Определения action.php:82
$arFilter
Определения user_search.php:106