Passed
Push — feature/Logging ( f3941b...f314df )
by Simon
06:52
created

SolrConfigureTask::logException()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 19
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 15
c 0
b 0
f 0
dl 0
loc 19
ccs 0
cts 14
cp 0
rs 9.7666
cc 2
nc 1
nop 2
crap 6
1
<?php
2
3
4
namespace Firesphere\SolrSearch\Tasks;
5
6
use Exception;
7
use Firesphere\SolrSearch\Helpers\SolrLogger;
8
use Firesphere\SolrSearch\Indexes\BaseIndex;
9
use Firesphere\SolrSearch\Interfaces\ConfigStore;
10
use Firesphere\SolrSearch\Models\SolrLog;
11
use Firesphere\SolrSearch\Services\SolrCoreService;
12
use Firesphere\SolrSearch\Stores\FileConfigStore;
13
use Firesphere\SolrSearch\Stores\PostConfigStore;
14
use Firesphere\SolrSearch\Traits\LoggerTrait;
15
use ReflectionException;
16
use RuntimeException;
17
use SilverStripe\Control\HTTPRequest;
18
use SilverStripe\Core\Injector\Injector;
19
use SilverStripe\Dev\BuildTask;
20
use SilverStripe\Dev\Debug;
21
use SilverStripe\ORM\ValidationException;
22
23
class SolrConfigureTask extends BuildTask
24
{
25
    use LoggerTrait;
26
27
    protected static $storeModes = [
28
        'file' => FileConfigStore::class,
29
        'post' => PostConfigStore::class,
30
//        'webdav' => WebdavConfigStore::class,
31
    ];
32
    private static $segment = 'SolrConfigureTask';
33
    protected $title = 'Configure Solr cores';
34
    protected $description = 'Create or reload a Solr Core by adding or reloading a configuration.';
35
36 26
    public function __construct()
37
    {
38 26
        parent::__construct();
39 26
    }
40
41
    /**
42
     * Implement this method in the task subclass to
43
     * execute via the TaskRunner
44
     *
45
     * @param HTTPRequest $request
46
     * @return bool|Exception
47
     * @throws ReflectionException
48
     * @throws ValidationException
49
     * @throws \GuzzleHttp\Exception\GuzzleException
50
     */
51 25
    public function run($request)
52
    {
53 25
        $this->extend('onBeforeSolrConfigureTask', $request);
54
55 25
        $indexes = (new SolrCoreService())->getValidIndexes();
56
57 25
        foreach ($indexes as $index) {
58
            try {
59 25
                $this->configureIndex($index);
60
            } catch (\Exception $error) {
61
                $this->getLogger()->error(sprintf('Core loading failed for %s', $index));
62
                // Continue to the next index
63
                continue;
64
            }
65 25
            $this->extend('onAfterConfigureIndex', $index);
66
        }
67
68 25
        $this->extend('onAfterSolrConfigureTask');
69
        // Grab the latest logs
70 25
        $solrLogger = new SolrLogger();
71 25
        $solrLogger->saveSolrLog('Config');
72
73 25
        return true;
74
    }
75
76
    /**
77
     * Update the index on the given store
78
     *
79
     * @param string $index
80
     * @throws ValidationException
81
     * @throws \GuzzleHttp\Exception\GuzzleException
82
     */
83 25
    protected function configureIndex($index): void
84
    {
85
        /** @var BaseIndex $instance */
86 25
        $instance = Injector::inst()->get($index, false);
87
88 25
        $index = $instance->getIndexName();
89
90
        // Then tell Solr to use those config files
91
        /** @var SolrCoreService $service */
92 25
        $service = Injector::inst()->get(SolrCoreService::class);
93
94
        // Assuming a core that doesn't exist doesn't have uptime, as per Solr docs
95
        // And it has a start time.
96
        // You'd have to be pretty darn fast to hit 0 uptime and 0 starttime for an existing core!
97 25
        $status = $service->coreStatus($index);
98 25
        $configStore = $this->createConfigForIndex($instance);
99
        // Default to create
100 25
        $method = 'coreCreate';
101
        // Switch to reload if the core is loaded
102 25
        if ($status && ($status->getUptime() && $status->getStartTime() !== null)) {
103 25
            $method = 'coreReload';
104
        }
105
        try {
106 25
            $service->$method($index, $configStore);
107 25
            $this->getLogger()->info(sprintf('Core %s successfully loaded', $index));
108
        } catch (\Exception $error) {
109
            $this->logException($index, $error);
110
            throw new RuntimeException($error);
111
        }
112 25
    }
113
114
    /**
115
     * @param BaseIndex $instance
116
     * @return ConfigStore
117
     */
118 25
    protected function createConfigForIndex(BaseIndex $instance): ConfigStore
119
    {
120 25
        $storeConfig = SolrCoreService::config()->get('store');
121 25
        $configStore = $this->getStore($storeConfig);
122 25
        $instance->uploadConfig($configStore);
123
124 25
        return $configStore;
125
    }
126
127
    /**
128
     * @param $storeConfig
129
     * @return ConfigStore
130
     */
131 25
    protected function getStore($storeConfig): ConfigStore
132
    {
133 25
        $store = static::$storeModes[$storeConfig['mode']];
134 25
        $configStore = Injector::inst()->create($store, $storeConfig);
135
136
        // Allow changing the configStore if it needs to change to a different store
137 25
        $this->extend('onBeforeConfig', $configStore, $storeConfig);
138
139 25
        return $configStore;
140
    }
141
142
    /**
143
     * @param $index
144
     * @param Exception $error
145
     * @throws ValidationException
146
     * @throws \GuzzleHttp\Exception\GuzzleException
147
     */
148
    protected function logException($index, Exception $error): void
149
    {
150
        $this->getLogger()->error($error);
151
        $solrLogger = new SolrLogger();
152
        $solrLogger->saveSolrLog('Config');
153
        /** @var SolrLog $lastError */
154
        $lastError = SolrLog::get()
155
            ->filter([
156
                'Index' => 'x:' . $index,
157
                'Level' => 'ERROR'
158
            ])
159
            ->sort('Created ASC')
160
            ->first();
161
        Debug::dump(sprintf(
162
            "Error loading core %s,\n" .
163
            "Please log in to the CMS to find out more about Configuration errors\n" .
164
            'Last known error: %s',
165
            $index,
166
            ($lastError === null) ? 'Unknown' : $lastError->getLastErrorLine()
167
        ));
168
    }
169
}
170