Completed
Push — master ( a88917...5cd682 )
by Maxence
02:41 queued 12s
created

RunningService::exception()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 10
rs 9.9332
cc 3
nc 3
nop 3
1
<?php
2
declare(strict_types=1);
3
4
5
/**
6
 * FullTextSearch - Full text search framework for Nextcloud
7
 *
8
 * This file is licensed under the Affero General Public License version 3 or
9
 * later. See the COPYING file.
10
 *
11
 * @author Maxence Lange <[email protected]>
12
 * @copyright 2018
13
 * @license GNU AGPL version 3 or any later version
14
 *
15
 * This program is free software: you can redistribute it and/or modify
16
 * it under the terms of the GNU Affero General Public License as
17
 * published by the Free Software Foundation, either version 3 of the
18
 * License, or (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU Affero General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU Affero General Public License
26
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27
 *
28
 */
29
30
31
namespace OCA\FullTextSearch\Service;
32
33
34
use Exception;
35
use OCA\FullTextSearch\Db\TickRequest;
36
use OCA\FullTextSearch\Exceptions\RunnerAlreadyUpException;
37
use OCA\FullTextSearch\Exceptions\TickDoesNotExistException;
38
use OCA\FullTextSearch\Exceptions\TickIsNotAliveException;
39
use OCA\FullTextSearch\Model\Tick;
40
41
42
/**
43
 * Class RunningService
44
 *
45
 * @package OCA\FullTextSearch\Service
46
 */
47
class RunningService {
48
49
50
	/** @var TickRequest */
51
	private $tickRequest;
52
53
	/** @var ConfigService */
54
	private $configService;
55
56
	/** @var MiscService */
57
	private $miscService;
58
59
60
	/**
61
	 * RunningService constructor.
62
	 *
63
	 * @param TickRequest $tickRequest
64
	 * @param ConfigService $configService
65
	 * @param MiscService $miscService
66
	 */
67
	public function __construct(
68
		TickRequest $tickRequest, ConfigService $configService, MiscService $miscService
69
	) {
70
		$this->tickRequest = $tickRequest;
71
		$this->configService = $configService;
72
		$this->miscService = $miscService;
73
	}
74
75
76
	/**
77
	 * @param string $source
78
	 *
79
	 * @return int
80
	 * @throws RunnerAlreadyUpException
81
	 * @throws Exception
82
	 */
83
	public function start(string $source): int {
84
85
		if ($this->isAlreadyRunning()) {
86
			throw new RunnerAlreadyUpException('Index is already running');
87
		}
88
89
		$tick = new Tick($source);
90
		$tick->setStatus('run')
91
			 ->setTick()
92
			 ->setFirstTick()
93
			 ->setInfoInt('runStart ', time());
94
95
		return $this->tickRequest->create($tick);
96
	}
97
98
99
	/**
100
	 * @param int $runId
101
	 * @param string $action
102
	 *
103
	 * @throws TickDoesNotExistException
104
	 * @throws TickIsNotAliveException
105
	 */
106
	public function update(int $runId, string $action = '') {
107
		$tick = $this->tickRequest->getTickById($runId);
108
109
		$this->isStillAlive($tick, true);
110
		$tick->setTick();
111
112
		if ($action !== '' && $action !== $tick->getAction()) {
113
			$this->assignActionToTick($tick, $action);
114
		}
115
116
		$this->tickRequest->update($tick);
117
	}
118
119
120
	/**
121
	 * @param int $runId
122
	 * @param string $reason
123
	 *
124
	 * @throws TickDoesNotExistException
125
	 */
126
	public function stop(int $runId, string $reason = '') {
127
		$tick = $this->tickRequest->getTickById($runId);
128
		$tick->setStatus('stop')
129
			 ->setTick()
130
			 ->setInfoInt('runStop', time())
131
			 ->setInfoInt('totalDocuments', 42);
132
133
		if ($reason !== '') {
134
			$tick->setStatus('exception');
135
			$tick->setInfo('exception', $reason);
136
		}
137
138
		$this->tickRequest->update($tick);
139
	}
140
141
142
	/**
143
	 * @param int $runId
144
	 *
145
	 * @return bool
146
	 * @throws TickIsNotAliveException
147
	 */
148
	public function isAlive(int $runId): bool {
149
		$tick = null;
150
		try {
151
			$tick = $this->tickRequest->getTickById($runId);
152
		} catch (TickDoesNotExistException $e) {
153
			return false;
154
		}
155
156
		return $this->isStillAlive($tick);
157
	}
158
159
160
	/**
161
	 * @param Tick $tick
162
	 * @param bool $exception
163
	 *
164
	 * @return bool
165
	 * @throws TickIsNotAliveException
166
	 */
167
	public function isStillAlive(Tick $tick, bool $exception = false): bool {
168
		if ($tick->getStatus() !== 'run') {
169
			if ($exception) {
170
				throw new TickIsNotAliveException();
171
			} else {
172
				return false;
173
			}
174
		}
175
176
		return true;
177
	}
178
179
180
	/**
181
	 * @return bool
182
	 */
183
	public function isAlreadyRunning(): bool {
184
		$ttl = (int) $this->configService->getAppValue(ConfigService::TICK_TTL);
185
		$ticks = $this->tickRequest->getTicksByStatus('run');
186
187
		$isAlreadyRunning = false;
188
		foreach ($ticks as $tick) {
189
			if ($tick->getTick() < (time() - $ttl)) {
190
				$tick->setStatus('timeout');
191
				$this->tickRequest->update($tick);
192
			} else {
193
				$isAlreadyRunning = true;
194
			}
195
		}
196
197
		return $isAlreadyRunning;
198
	}
199
200
201
	/**
202
	 *
203
	 */
204
	public function forceStop() {
205
		$ticks = $this->tickRequest->getTicksByStatus('run');
206
207
		foreach ($ticks as $tick) {
208
			$tick->setStatus('forceStop');
209
			$this->tickRequest->update($tick);
210
		}
211
	}
212
213
214
	/**
215
	 * @param Tick $tick
216
	 * @param string $action
217
	 */
218
	private function assignActionToTick(Tick &$tick, string $action) {
219
		$now = microtime(true);
220
		$preAction = $tick->getAction();
221
222
		if ($preAction !== '') {
223
			$preActionTotal = $tick->getInfoFloat($preAction . 'Total', 0);
224
			$preActionStart = $tick->getInfoFloat($preAction . 'Init', 0);
225
226
			if ($preActionStart > 0) {
227
228
				$preActionTotal += ($now - $preActionStart);
229
				$tick->setInfoFloat($preAction . 'Total', $preActionTotal);
230
				$tick->unsetInfo($preAction . 'Init');
231
			}
232
		}
233
		$tick->setAction($action)
234
			 ->setInfoFloat($action . 'Init', $now);
235
	}
236
237
238
}
239