I finally have two BrainRunners working on a DigitalOcean droplet, and one BrainHub on another droplet queueing and assigning tasks to the runners.

It’s still rough, but let’s start with the BrainHub’s scheduled artisan commands (Artisan is the CLI that comes with Laravel):

QueueIdleBrainChecks runs every minute.

	public function handle()
	{
        // Find snail due for brain check.
        $snailController = new SnailController();
        $allIdleSnails = $snailController->getAllIdleSnails();

        foreach ($allIdleSnails as $snail) {
            // Seconds since last brain check
            $diff = Carbon::now()->diffInSeconds (Carbon::parse($snail->brainCheckedAt));
            if ($diff >= 60) {
                $existingQueuedBrainCheck = QueuedBrain::where('snailID', '=', $snail->snailID)->first();
                // If brain check is not already queued, queue a new check
                if ($existingQueuedBrainCheck === null) {
                    $queuedBrain = new QueuedBrain();
                    $queuedBrain->snailID = $snail->snailID;
                    $queuedBrain->save();
                }
            }
        }
	}

{:lang=“php”}

This basically just gets all living idle snails from the snail_life db and creates a new brain check entry in the brain_hub db.

Also every minute we run the AssignBrainsToRunners artisan command:

	public function handle()
	{
        $brainRunnerRetriever = new BrainRunnerRetriever();
        $allIdleBrainRunners = $brainRunnerRetriever->getAllIdleBrainRunners();
        $taskRetriever = new TaskRetriever();
        foreach ($allIdleBrainRunners as $brainRunner) {
            $task = $taskRetriever->GetNextQueuedTask();
            if ($task !== null) {
                $brainRunner->assignQueuedTask ($task);
            }
        }
	}

{:lang=“php”}

This finds any available (idle) brain runners and assigns the next queued tasks to them.

In the BrainRunner model:

    public function assignQueuedTask($task) {
        // Change status of BrainRunner to 1 - Busy
        $this->updateStatusCode(1);
        $url = $this->url() . DIRECTORY_SEPARATOR . 'api/runTask';
        Log::info('assignQueuedTask testurl: ' . $url);
        $postfields = 'taskID=' . $task->id . '&snailID=' . $task->snailID . '&runnerID=' . $this->id . '&hubURL=' . env('APP_URL');

        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_URL => $url,
            CURLOPT_POST => 1,
            CURLOPT_POSTFIELDS => $postfields,
            CURLOPT_TIMEOUT_MS => 2500
        ));
        $resp = curl_exec($curl);
        curl_close($curl);

        // Delete task from queue
        $task->delete();
    }

{:lang=“php”}

The brain runner then runs the task:

    public function RunTask($task) {
        try{
            $this->taskID = $task['taskID'];
            $this->hubURL = $task['hubURL'];
            $this->runnerID = $task['runnerID'];

            // Get runner specific logger
            $utility = new Utility($this->taskID);
            $logger = $utility->logger;
            $snailController = new SnailController();
            $logger->addInfo('INFO: RunTask: Initialized SnailActionController');

            // The recurring event is actually not required anymore,
            // but we kind of hack it together because before the BrainHub
            // the snail brains relied on it and still do temporarily.
            $event = new RecurringEvent();
            $event->name = 'IdleSnailAction';
            $logger->addInfo('INFO: RunTask: Initialized IdleSnailAction Event');

            // Find the snail
            $snail = $snailController->findSnail($task['snailID']);
            if ($snail === null) {
                $logger->addError('ERROR: Snail ID ' . $task['snailID'] . ' NOT FOUND.');
            }
            else {
                $logger->addInfo ('INFO: RunTask: Found Snail ID: ' . $snail->snailID);
                $snailActionCoordinator = new SnailActionCoordinator();
                $snailActionCoordinator->checkAction([$snail], 60, $event);
                $logger->addInfo ('INFO: RunTask: Action Checked');
            }

            $logger->addInfo ('INFO: RunTask: Reported task as finished');

            // Save log to S3 (might rip this out later as we don't need to keep that many logs anyway)
            $utility->saveLog($this->runnerID);
        }
        catch(\Exception $e){
            $logger->addError('ERROR: RunTask: Exception Caught, cancelling task');
            $logger->addError($e);
        }
        $this->reportTaskFinish();
    }

{:lang=“php”}

The BrainHub connects to both the main SnailLife database and the BrainHub database. BrainRunners can only connect to the SnailLife database. The only thing that ever reads from or modifies the BrainHub DB is the BrainHub itself.

SnailLife logo and website

I have been getting really sick of looking at the ugly black and white SnailLife website. So I decided to try and make it a little more exciting. It’s still ugly, but at least it’s colorful-ugly now! I stumbled across a bunch of open source logos over at Logodust. I felt like taking a break from the BrainHub for a while and messed around with combining two of the logos and adding an eye stalk to make something vaguely resembling a snail. The logo is also quite versatile in case I ever decide to ditch the snail idea, since I’ve been told it looks like a chinchilla or one of those deep water fish with the light in front of its face as well…

SnailLife logo

So now the site is, though by no means great, just a little less bland:

SnailLife website