public function main()
    {
        declare(ticks = 1);
        pcntl_signal(SIGINT, function () {
            exit(0);
        });

        $kubernetesClient = $this->getKubernetesClient();
        $storeEnabled = $this->getStoreEnabled();

        if ($storeEnabled) {
            $this->store = new Store($this);
            $this->store->init();
        }

        $watches = new \KubernetesClient\WatchCollection();

        $configMapNamespace = $this->getConfigMapNamespace();
        $configMapName = $this->getConfigMapName();

        $storeNamespace = $this->getStoreNamespace();
        $storeName = $this->getStoreName();

        //controller config
        $watch = $kubernetesClient->createWatch("/api/v1/watch/namespaces/${configMapNamespace}/configmaps/${configMapName}", [], $this->getConfigMapWatchCallback());
        $watches->addWatch($watch);

        while (true) {
            usleep(100 * 1000);
            $watches->start(1);

            // do NOT perform anything until config is loaded
            if (!$this->getConfigLoaded()) {
                $this->log("waiting for ConfigMap ${configMapNamespace}/${configMapName} to be present and valid");
                sleep(5);
                continue;
            }

            // do NOT perform anything until store is ready
            if ($storeEnabled) {
                if (!$this->store->initialized()) {
                    $this->log("waiting for store ConfigMap ${storeNamespace}/${storeName} to be present and valid");
                    $this->store->init();
                    sleep(5);
                    continue;
                }
            }

            // update store data
            if ($storeEnabled) {
                $this->store->readWatches();
            }

            // process plugins
            foreach ($this->plugins as $plugin) {
                $plugin->preReadWatches();
                $plugin->readWatches();
                $plugin->postReadWatches();

                if ($plugin->getActionRequired()) {
                    // be patient in failure scenarios
                    if (!$plugin->getLastActionSuccess() && ((time() - $this->failedActionWaitTime) <= $plugin->getLastActionAttemptTime())) {
                        continue;
                    }

                    // wait for settle time
                    $settleTime = $plugin->getSettleTime();
                    $actionRequiredTime = $plugin->getActionRequiredTime();
                    if ($settleTime > 0 &&
                        $actionRequiredTime > 0 &&
                        ((time() - $actionRequiredTime) <= $settleTime)) {
                        continue;
                    }

                    // wait for throttle time
                    $throttleTime = $plugin->getThrottleTime();
                    $lastActionAttemptTime = $plugin->getLastActionAttemptTime();
                    if ($throttleTime > 0 &&
                        $lastActionAttemptTime > 0 &&
                        ((time() - $lastActionAttemptTime) <= $throttleTime)) {
                        continue;
                    }

                    $plugin->invokeAction();
                }
            }

            // update store data
            if ($storeEnabled) {
                $this->store->readWatches();
            }
        }
    }