Scalr\System\Zmq\Cron\Task\Scaling::worker PHP Méthode

worker() public méthode

See also: Scalr\System\Zmq\Cron\TaskInterface::worker()
public worker ( $request )
    public function worker($request)
    {
        //Warming up static DI cache
        \Scalr::getContainer()->warmup();
        // Reconfigure observers
        \Scalr::ReconfigureObservers();
        if (!isset($request->farmRoleId)) {
            //This is the farm with synchronous launch of roles
            try {
                $DBFarm = DBFarm::LoadByID($request->farmId);
                if ($DBFarm->Status != FARM_STATUS::RUNNING) {
                    $this->getLogger()->warn("[FarmID: %d] Farm isn't running. There is no need to scale it.", $DBFarm->ID);
                    return false;
                }
            } catch (Exception $e) {
                $this->getLogger()->error("Could not load farm '%s' with ID:%d", $request->farmName, $request->farmId);
                throw $e;
            }
            //Gets the list of the roles
            $list = $DBFarm->GetFarmRoles();
        } else {
            //This is asynchronous lauhch
            try {
                $DBFarmRole = DBFarmRole::LoadByID($request->farmRoleId);
                if ($DBFarmRole->getFarmStatus() != FARM_STATUS::RUNNING) {
                    //We don't need to handle inactive farms
                    return false;
                }
            } catch (Exception $e) {
                $this->getLogger()->error("Could not load FarmRole with ID:%d", $request->farmRoleId);
                throw $e;
            }
            $list = [$DBFarmRole];
        }
        $this->getLogger()->debug("Processing %s FarmRoles", count($list));
        foreach ($list as $DBFarmRole) {
            // Set Last polling time
            $DBFarmRole->SetSetting(Entity\FarmRoleSetting::SCALING_LAST_POLLING_TIME, time(), Entity\FarmRoleSetting::TYPE_LCL);
            $disabledScaling = false;
            if ($DBFarmRole->GetSetting(Entity\FarmRoleSetting::SCALING_ENABLED) != '1') {
                if ($DBFarmRole->GetRoleObject()->hasBehavior(ROLE_BEHAVIORS::RABBITMQ) || $DBFarmRole->GetRoleObject()->hasBehavior(ROLE_BEHAVIORS::VPC_ROUTER)) {
                    // For Mongo, RabbitMQ and VPC Router we need to launch first instance (or maintain 1 instance running)
                    // When 1 instance is already running, the rest is fully manual
                    $roleTotalInstances = $DBFarmRole->GetRunningInstancesCount() + $DBFarmRole->GetPendingInstancesCount();
                    if ($roleTotalInstances != 0) {
                        $disabledScaling = true;
                    }
                } else {
                    if (!$DBFarmRole->GetRoleObject()->hasBehavior(ROLE_BEHAVIORS::MONGODB)) {
                        $disabledScaling = true;
                    }
                }
                if ($disabledScaling) {
                    $this->getLogger()->info("[FarmID: %d] Scaling is disabled for role '%s'. Skipping...", $request->farmId, $DBFarmRole->Alias);
                    continue;
                }
            }
            $farmRoleName = $DBFarmRole->Alias ? $DBFarmRole->Alias : $DBFarmRole->GetRoleObject()->name;
            // Get current count of running and pending instances.
            $this->getLogger()->info(sprintf("Processing role '%s'", $farmRoleName));
            $scalingManager = new Scalr_Scaling_Manager($DBFarmRole);
            //Replacing the logger
            $scalingManager->logger = $this->getLogger();
            $scalingDecision = $scalingManager->makeScalingDecision();
            $scalingDecisionDetails = $scalingManager->decisonInfo;
            $this->getLogger()->info(sprintf("Decision '%s' (%s)", $scalingDecision, $scalingDecisionDetails));
            if ($scalingDecision == Scalr_Scaling_Decision::STOP_SCALING) {
                return;
            }
            if ($scalingDecision == Scalr_Scaling_Decision::NOOP) {
                continue;
            } else {
                if ($scalingDecision == Scalr_Scaling_Decision::DOWNSCALE) {
                    /*
                     Timeout instance's count decrease. Decreases instances count after scaling
                     resolution the spare instances are running for selected timeout interval
                     from scaling EditOptions
                    */
                    // We have to check timeout limits before new scaling (downscaling) process will be initiated
                    if ($DBFarmRole->GetSetting(Entity\FarmRoleSetting::SCALING_DOWNSCALE_TIMEOUT_ENABLED)) {
                        // if the farm timeout is exceeded
                        // checking timeout interval.
                        $last_down_scale_data_time = $DBFarmRole->GetSetting(Entity\FarmRoleSetting::SCALING_DOWNSCALE_DATETIME);
                        $timeout_interval = $DBFarmRole->GetSetting(Entity\FarmRoleSetting::SCALING_DOWNSCALE_TIMEOUT);
                        // check the time interval to continue scaling or cancel it...
                        if (time() - $last_down_scale_data_time < $timeout_interval * 60) {
                            // if the launch time is too small to terminate smth in this role -> go to the next role in foreach()
                            \Scalr::getContainer()->logger(LOG_CATEGORY::FARM)->info(new FarmLogMessage(!empty($request->farmId) ? $request->farmId : null, sprintf("Waiting for downscaling timeout on farm %s, role %s", !empty($request->farmName) ? $request->farmName : null, !empty($DBFarmRole->Alias) ? $DBFarmRole->Alias : null), null, null, !empty($DBFarmRole->ID) ? $DBFarmRole->ID : null));
                            continue;
                        }
                    }
                    // end Timeout instance's count decrease
                    $sort = $DBFarmRole->GetSetting(Entity\FarmRoleSetting::SCALING_KEEP_OLDEST) == 1 ? 'DESC' : 'ASC';
                    $servers = $this->db->GetAll("SELECT server_id FROM servers WHERE status = ? AND farm_roleid=? ORDER BY dtadded {$sort}", array(SERVER_STATUS::RUNNING, $DBFarmRole->ID));
                    $got_valid_instance = false;
                    $ignoreFullHour = $DBFarmRole->GetSetting(Entity\FarmRoleSetting::SCALING_IGNORE_FULL_HOUR);
                    $useSafeShutdown = $DBFarmRole->GetSetting(Entity\FarmRoleSetting::SCALING_SAFE_SHUTDOWN);
                    $isRabbitMQ = $DBFarmRole->GetRoleObject()->hasBehavior(ROLE_BEHAVIORS::RABBITMQ);
                    // Select instance that will be terminated
                    //
                    // Instances ordered by uptime (oldest wil be choosen)
                    // Instance cannot be mysql master
                    // Choose the one that was rebundled recently
                    $DBServer = null;
                    while (!$got_valid_instance && count($servers) > 0) {
                        $item = array_shift($servers);
                        $DBServer = DBServer::LoadByID($item['server_id']);
                        if ($isRabbitMQ) {
                            $serverExists = $this->db->GetOne("\n                            SELECT EXISTS (\n                                SELECT 1 FROM servers\n                                WHERE farm_roleid = ?\n                                AND status NOT IN (?, ?)\n                                AND `index` != ?\n                            )\n                        ", [$DBServer->farmRoleId, SERVER_STATUS::TERMINATED, SERVER_STATUS::SUSPENDED, 1]);
                            if ($DBServer->index == 1 && $serverExists) {
                                continue;
                            }
                        }
                        if ($DBServer->GetProperty(EC2_SERVER_PROPERTIES::IS_LOCKED)) {
                            continue;
                        }
                        // Exclude db master
                        if ($DBServer->GetProperty(SERVER_PROPERTIES::DB_MYSQL_MASTER) != 1 && $DBServer->GetProperty(Scalr_Db_Msr::REPLICATION_MASTER) != 1) {
                            $got_valid_instance = true;
                        }
                        //Check safe shutdown
                        if ($useSafeShutdown == 1) {
                            try {
                                $res = $DBServer->scalarizr->system->callAuthShutdownHook();
                            } catch (Exception $e) {
                                $res = $e->getMessage();
                            }
                            if ($res != '1') {
                                \Scalr::getContainer()->logger(LOG_CATEGORY::FARM)->info(new FarmLogMessage($DBServer->farmId, sprintf("Safe shutdown enabled. Server '%s'. Script returned '%s' skipping it.", $DBServer->serverId, $res), $DBServer->serverId, $DBServer->envId, $DBServer->farmRoleId));
                                $got_valid_instance = false;
                            }
                        }
                    }
                    // end while
                    if ($DBServer !== null && $got_valid_instance) {
                        $this->getLogger()->info(sprintf("Server '%s' selected for termination...", $DBServer->serverId));
                        $allow_terminate = false;
                        if ($DBServer->platform == SERVER_PLATFORMS::EC2) {
                            $aws = $DBServer->GetEnvironmentObject()->aws($DBServer);
                            // Shutdown an instance just before a full hour running
                            if (!$ignoreFullHour) {
                                $response = $aws->ec2->instance->describe($DBServer->GetProperty(EC2_SERVER_PROPERTIES::INSTANCE_ID))->get(0);
                                if ($response && count($response->instancesSet)) {
                                    $launch_time = $response->instancesSet->get(0)->launchTime->getTimestamp();
                                    $time = 3600 - (time() - $launch_time) % 3600;
                                    // Terminate instance in < 10 minutes for full hour.
                                    if ($time <= 600) {
                                        $allow_terminate = true;
                                    } else {
                                        $timeout = round(($time - 600) / 60, 1);
                                        \Scalr::getContainer()->logger(LOG_CATEGORY::FARM)->info(new FarmLogMessage($request->farmId, sprintf("Role '%s' scaling down (%s). Server '%s' will be terminated in %s minutes. Launch time: %s", $DBServer->GetFarmRoleObject()->Alias, $scalingDecisionDetails, $DBServer->serverId, $timeout, $response->instancesSet->get(0)->launchTime->format('c')), $DBServer->serverId, $DBServer->envId, $DBServer->farmRoleId));
                                    }
                                }
                            } else {
                                $allow_terminate = true;
                            }
                            //Releases memory
                            $DBServer->GetEnvironmentObject()->getContainer()->release('aws');
                            unset($aws);
                        } else {
                            $allow_terminate = true;
                        }
                        if ($allow_terminate) {
                            $terminateStrategy = $DBFarmRole->GetSetting(Scalr_Role_Behavior::ROLE_BASE_TERMINATE_STRATEGY);
                            if (!$terminateStrategy) {
                                $terminateStrategy = 'terminate';
                            }
                            try {
                                if ($terminateStrategy == 'terminate') {
                                    $DBServer->terminate(DBServer::TERMINATE_REASON_SCALING_DOWN, false);
                                    $DBFarmRole->SetSetting(Entity\FarmRoleSetting::SCALING_DOWNSCALE_DATETIME, time(), Entity\FarmRoleSetting::TYPE_LCL);
                                    \Scalr::getContainer()->logger(LOG_CATEGORY::FARM)->info(new FarmLogMessage($request->farmId, sprintf("Role '%s' scaling down (%s). Server '%s' marked as 'Pending terminate' and will be fully terminated in 3 minutes.", $DBServer->GetFarmRoleObject()->Alias, $scalingDecisionDetails, $DBServer->serverId), $DBServer->serverId, $DBServer->envId, $DBServer->farmRoleId));
                                } else {
                                    $DBServer->suspend('SCALING_DOWN', false);
                                    $DBFarmRole->SetSetting(Entity\FarmRoleSetting::SCALING_DOWNSCALE_DATETIME, time(), Entity\FarmRoleSetting::TYPE_LCL);
                                    \Scalr::getContainer()->logger(LOG_CATEGORY::FARM)->info(new FarmLogMessage($request->farmId, sprintf("Role '%s' scaling down (%s). Server '%s' marked as 'Pending suspend' and will be fully suspended in 3 minutes.", $DBServer->GetFarmRoleObject()->Alias, $scalingDecisionDetails, $DBServer->serverId), $DBServer->serverId, $DBServer->envId, $DBServer->farmRoleId));
                                }
                            } catch (Exception $e) {
                                $this->getLogger()->fatal(sprintf("Cannot %s %s: %s", $terminateStrategy, $request->farmId, $DBServer->serverId));
                            }
                        }
                    } else {
                        $this->getLogger()->warn(sprintf("[FarmID: %s] Scalr unable to determine what instance it should terminate (FarmRoleID: %s). Skipping...", $request->farmId, $DBFarmRole->ID));
                    }
                    //break;
                } elseif ($scalingDecision == Scalr_Scaling_Decision::UPSCALE) {
                    /*
                    Timeout instance's count increase. Increases  instance's count after
                    scaling resolution 'need more instances' for selected timeout interval
                    from scaling EditOptions
                    */
                    if ($DBFarmRole->GetSetting(Entity\FarmRoleSetting::SCALING_UPSCALE_TIMEOUT_ENABLED)) {
                        // if the farm timeout is exceeded
                        // checking timeout interval.
                        $last_up_scale_data_time = $DBFarmRole->GetSetting(Entity\FarmRoleSetting::SCALING_UPSCALE_DATETIME);
                        $timeout_interval = $DBFarmRole->GetSetting(Entity\FarmRoleSetting::SCALING_UPSCALE_TIMEOUT);
                        // check the time interval to continue scaling or cancel it...
                        if (time() - $last_up_scale_data_time < $timeout_interval * 60) {
                            // if the launch time is too small to terminate smth in this role -> go to the next role in foreach()
                            \Scalr::getContainer()->logger(LOG_CATEGORY::FARM)->info(sprintf("Waiting for upscaling timeout on farm %s, role %s", $request->farmName, $DBFarmRole->Alias));
                            continue;
                        }
                    }
                    // end Timeout instance's count increase
                    //Check DBMsr. Do not start slave during slave2master process
                    $isDbMsr = $DBFarmRole->GetRoleObject()->getDbMsrBehavior();
                    if ($isDbMsr) {
                        if ($DBFarmRole->GetSetting(Scalr_Db_Msr::SLAVE_TO_MASTER)) {
                            $runningServers = $DBFarmRole->GetRunningInstancesCount();
                            if ($runningServers > 0) {
                                \Scalr::getContainer()->logger(LOG_CATEGORY::FARM)->warn(new FarmLogMessage($request->farmId, sprintf("Role is in slave2master promotion process. Do not launch new slaves while there is no active slaves")));
                                continue;
                            } else {
                                $DBFarmRole->SetSetting(Scalr_Db_Msr::SLAVE_TO_MASTER, 0, Entity\FarmRoleSetting::TYPE_LCL);
                            }
                        }
                    }
                    if ($DBFarmRole->GetSetting(Entity\FarmRoleSetting::SCALING_ONE_BY_ONE) == 1) {
                        $pendingInstances = $DBFarmRole->GetPendingInstancesCount();
                        if ($pendingInstances > 0) {
                            \Scalr::getContainer()->logger(LOG_CATEGORY::FARM)->info(new FarmLogMessage($request->farmId, sprintf("There are %s pending intances of %s role on % farm. Waiting...", $pendingInstances, $DBFarmRole->Alias, $request->farmName)));
                            continue;
                        }
                    }
                    $fstatus = $this->db->GetOne("SELECT status FROM farms WHERE id=? LIMIT 1", array($request->farmId));
                    if ($fstatus != FARM_STATUS::RUNNING) {
                        $this->getLogger()->warn("[FarmID: {$request->farmId}] Farm terminated. There is no need to scale it.");
                        return;
                    }
                    $terminateStrategy = $DBFarmRole->GetSetting(Scalr_Role_Behavior::ROLE_BASE_TERMINATE_STRATEGY);
                    if (!$terminateStrategy) {
                        $terminateStrategy = 'terminate';
                    }
                    $suspendedServer = null;
                    if ($terminateStrategy == 'suspend') {
                        $suspendedServers = $DBFarmRole->GetServersByFilter(array('status' => SERVER_STATUS::SUSPENDED));
                        if (count($suspendedServers) > 0) {
                            $suspendedServer = array_shift($suspendedServers);
                        }
                    }
                    if ($terminateStrategy == 'suspend' && $suspendedServer) {
                        \Scalr::getContainer()->logger(LOG_CATEGORY::FARM)->warn(new FarmLogMessage($request->farmId, sprintf("Role '%s' scaling up (%s). Found server to resume. ServerID = %s.", $suspendedServer->GetFarmRoleObject()->Alias, $scalingDecisionDetails, $suspendedServer->serverId), $suspendedServer->serverId, $suspendedServer->envId, $suspendedServer->farmRoleId));
                    }
                    if ($terminateStrategy == 'terminate' || !$suspendedServer || !PlatformFactory::isOpenstack($suspendedServer->platform) && $suspendedServer->platform != SERVER_PLATFORMS::EC2 && $suspendedServer->platform != SERVER_PLATFORMS::GCE) {
                        $ServerCreateInfo = new ServerCreateInfo($DBFarmRole->Platform, $DBFarmRole);
                        try {
                            $DBServer = \Scalr::LaunchServer($ServerCreateInfo, null, false, DBServer::LAUNCH_REASON_SCALING_UP);
                            $DBFarmRole->SetSetting(Entity\FarmRoleSetting::SCALING_UPSCALE_DATETIME, time(), Entity\FarmRoleSetting::TYPE_LCL);
                            \Scalr::getContainer()->logger(LOG_CATEGORY::FARM)->info(new FarmLogMessage($request->farmId, sprintf("Role '%s' scaling up (%s). Starting new instance. ServerID = %s.", $DBServer->GetFarmRoleObject()->Alias, $scalingDecisionDetails, $DBServer->serverId), $DBServer->serverId, $DBServer->envId, $DBServer->farmRoleId));
                        } catch (Exception $e) {
                            \Scalr::getContainer()->logger(LOG_CATEGORY::SCALING)->error($e->getMessage());
                        }
                    } else {
                        $platform = PlatformFactory::NewPlatform($suspendedServer->platform);
                        $platform->ResumeServer($suspendedServer);
                    }
                }
            }
        }
        return true;
    }