Skip to content

Commit 658e61e

Browse files
authored
Merge pull request #8565 from ProcessMaker/task/FOUR-27352
Refactor for a single horizon instance to improve memory
2 parents 49ae243 + 994fd78 commit 658e61e

File tree

13 files changed

+233
-115
lines changed

13 files changed

+233
-115
lines changed

ProcessMaker/Http/Controllers/Admin/QueuesController.php

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,28 @@
55
use Illuminate\Auth\Access\AuthorizationException;
66
use ProcessMaker\Events\QueueManagementAccessed;
77
use ProcessMaker\Http\Controllers\Controller;
8+
use ProcessMaker\Providers\TenantQueueServiceProvider;
89

910
class QueuesController extends Controller
1011
{
1112
public function index()
1213
{
13-
if (auth()->user()->is_administrator) {
14-
// Register the Event
15-
QueueManagementAccessed::dispatch();
14+
if (!auth()->user()->is_administrator) {
15+
throw new AuthorizationException();
16+
}
1617

17-
return view('admin.queues.index');
18+
if (config('app.multitenancy')) {
19+
if (!TenantQueueServiceProvider::allowAllTenats()) {
20+
// Its multitenancy and they don't have access to all tenants so
21+
// redirect to the tenant-filtered queue management page.
22+
// Otherwise, show the horizon queue manager.
23+
return redirect()->route('tenant-queue.index');
24+
}
1825
}
1926

20-
throw new AuthorizationException();
27+
// Register the Event
28+
QueueManagementAccessed::dispatch();
29+
30+
return view('admin.queues.index');
2131
}
2232
}

ProcessMaker/Http/Controllers/Admin/TenantQueueController.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,20 @@ class TenantQueueController extends Controller
2020
public function __construct()
2121
{
2222
// Check if tenant job tracking is enabled
23-
$enabled = config('queue.tenant_tracking_enabled', false);
23+
$enabled = TenantQueueServiceProvider::enabled();
2424

2525
if (!$enabled) {
2626
if (!app()->runningInConsole()) {
2727
abort(404, 'Tenant queue tracking is disabled');
2828
}
2929
}
30+
31+
// If the route binding has a tenant id, check if the user is allowed to access the tenant queue
32+
if ($id = (int) request()->route('tenantId')) {
33+
if (!TenantQueueServiceProvider::allowAllTenats() && $id !== app('currentTenant')?->id) {
34+
throw new AuthorizationException();
35+
}
36+
}
3037
}
3138

3239
/**
@@ -52,6 +59,12 @@ public function getTenants(): JsonResponse
5259

5360
$tenantsWithJobs = TenantQueueServiceProvider::getTenantsWithJobs();
5461

62+
if (!TenantQueueServiceProvider::allowAllTenats()) {
63+
$tenantsWithJobs = array_filter($tenantsWithJobs, function ($tenantData) {
64+
return (int) $tenantData['id'] === app('currentTenant')?->id;
65+
});
66+
}
67+
5568
// Enrich with tenant information
5669
$tenants = [];
5770
foreach ($tenantsWithJobs as $tenantData) {
@@ -118,6 +131,12 @@ public function getOverallStats(): JsonResponse
118131

119132
$tenantsWithJobs = TenantQueueServiceProvider::getTenantsWithJobs();
120133

134+
if (!TenantQueueServiceProvider::allowAllTenats()) {
135+
$tenantsWithJobs = array_filter($tenantsWithJobs, function ($tenantData) {
136+
return (int) $tenantData['id'] === app('currentTenant')?->id;
137+
});
138+
}
139+
121140
$overallStats = [
122141
'total_tenants' => count($tenantsWithJobs),
123142
'total_jobs' => 0,

ProcessMaker/Multitenancy/MakeQueueTenantAwareAction.php

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,16 @@
22

33
namespace ProcessMaker\Multitenancy;
44

5-
use Illuminate\Queue\Events\JobProcessing;
6-
use Illuminate\Queue\Events\JobRetryRequested;
7-
use Illuminate\Support\Facades\Context;
85
use Spatie\Multitenancy\Actions\MakeQueueTenantAwareAction as BaseMakeQueueTenantAwareAction;
96

107
class MakeQueueTenantAwareAction extends BaseMakeQueueTenantAwareAction
118
{
12-
/*
13-
* We need to override this method because spatie will throw an error if the tenant is not found.
14-
* However, we want to support non-multitenant instances. If the tenant is not found,
15-
* run the job without a tenant.
16-
*/
17-
protected function bindOrForgetCurrentTenant(JobProcessing|JobRetryRequested $event): void
9+
/**
10+
* We're handling tenant aware queues manually, however, we still need to implement this because for some
11+
* reason the Spatie package calls it in Multitenancy::start(), weather it's a configured action or not.
12+
*/
13+
public function execute() : void
1814
{
19-
$tenantId = Context::get($this->currentTenantContextKey());
20-
if (!$tenantId) {
21-
// No need to do anything. Let the job run without a tenant.
22-
return;
23-
}
24-
25-
parent::bindOrForgetCurrentTenant($event);
15+
// Do nothing
2616
}
2717
}

ProcessMaker/Multitenancy/TenantAwareDispatcher.php

Lines changed: 0 additions & 31 deletions
This file was deleted.

ProcessMaker/Multitenancy/TenantBootstrapper.php

Lines changed: 47 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,33 @@
1717
*/
1818
class TenantBootstrapper
1919
{
20+
private static $landlordValues = [];
21+
2022
private $encrypter = null;
2123

2224
private $pdo = null;
2325

24-
private $originalValues = null;
26+
private $app = null;
27+
28+
public static $landlordKeysToSave = [
29+
'APP_URL',
30+
'APP_KEY',
31+
'LOG_PATH',
32+
'DB_USERNAME',
33+
'DB_PASSWORD',
34+
'REDIS_PREFIX',
35+
'CACHE_SETTING_PREFIX',
36+
'SCRIPT_MICROSERVICE_CALLBACK',
37+
];
2538

2639
public function bootstrap(Application $app)
2740
{
2841
if (!$this->env('MULTITENANCY')) {
2942
return;
3043
}
44+
$this->app = $app;
3145

32-
// We need to save the original values for running horizon
33-
$this->saveOriginalValues();
46+
self::saveLandlordValues($app);
3447

3548
$tenantData = null;
3649

@@ -49,26 +62,26 @@ public function bootstrap(Application $app)
4962

5063
return;
5164
}
52-
$this->setTenantEnvironmentVariables($app, $tenantData);
65+
66+
// Set storage path
67+
$app->useStoragePath($app->basePath('storage/tenant_' . $tenantData['id']));
68+
69+
$this->setTenantEnvironmentVariables($tenantData);
5370

5471
// Use tenant's translation files. Doing this here so it's available in cached filesystems.php
5572
$app->useLangPath(resource_path('lang/tenant_' . $tenantData['id']));
5673

57-
$tenantData['original_values'] = $this->getOriginalValue();
74+
$tenantData['original_values'] = self::$landlordValues;
5875
Tenant::setBootstrappedTenant($app, $tenantData);
5976
}
6077

61-
private function setTenantEnvironmentVariables($app, $tenantData)
78+
private function setTenantEnvironmentVariables($tenantData)
6279
{
6380
// Additional configs are set in SwitchTenant.php
6481

65-
$tenantId = $tenantData['id'];
6682
$config = json_decode($tenantData['config'], true);
6783

68-
$this->set('APP_CONFIG_CACHE', $app->basePath('storage/tenant_' . $tenantId . '/config.php'));
69-
// Do not override packages cache path for now. Wait until the License service is updated.
70-
// $this->set('APP_PACKAGES_CACHE', $app->basePath('storage/tenant_' . $tenantId . '/packages.php'));
71-
$this->set('LARAVEL_STORAGE_PATH', $app->basePath('storage/tenant_' . $tenantId));
84+
$this->set('APP_CONFIG_CACHE', $this->app->storagePath('config.php'));
7285
$this->set('APP_URL', $config['app.url']);
7386
$this->set('APP_KEY', $this->decrypt($config['app.key']));
7487
$this->set('DB_DATABASE', $tenantData['database']);
@@ -83,51 +96,48 @@ private function setTenantEnvironmentVariables($app, $tenantData)
8396
}
8497

8598
$this->set('DB_PASSWORD', $password);
86-
$this->set('REDIS_PREFIX', $this->getOriginalValue('REDIS_PREFIX') . 'tenant-' . $tenantId . ':');
87-
$this->set('LOG_PATH', $app->basePath('storage/tenant_' . $tenantId . '/logs/processmaker.log'));
99+
$this->set('LOG_PATH', $this->app->storagePath('logs/processmaker.log'));
88100
}
89101

90-
private function saveOriginalValues()
102+
public static function saveLandlordValues($app)
91103
{
92-
if ($this->env('ORIGINAL_VALUES')) {
104+
if ($app->has('landlordValues')) {
105+
self::$landlordValues = $app->make('landlordValues');
106+
93107
return;
94108
}
95-
$toSave = [
96-
'APP_URL',
97-
'APP_KEY',
98-
'DB_USERNAME',
99-
'DB_PASSWORD',
100-
'REDIS_PREFIX',
101-
'CACHE_SETTING_PREFIX',
102-
'SCRIPT_MICROSERVICE_CALLBACK',
103-
];
104-
$values = [];
105-
foreach ($toSave as $key) {
106-
$values[$key] = $this->env($key);
109+
110+
foreach (self::$landlordKeysToSave as $key) {
111+
self::$landlordValues[$key] = $_SERVER[$key] ?? '';
107112
}
108-
$this->set('ORIGINAL_VALUES', serialize($values));
109113
}
110114

111-
private function getOriginalValue($key = null)
115+
private function getOriginalValue($key)
112116
{
113-
if (!$this->originalValues) {
114-
$this->originalValues = unserialize($this->env('ORIGINAL_VALUES'));
115-
}
116-
if (!$key) {
117-
return $this->originalValues;
117+
if (!isset(self::$landlordValues[$key])) {
118+
return '';
118119
}
119120

120-
return $this->originalValues[$key];
121+
return self::$landlordValues[$key];
121122
}
122123

123124
private function env($key, $default = null)
124125
{
125-
return Env::get($key, $default);
126+
$value = $_SERVER[$key] ?? $default;
127+
if ($value === 'true') {
128+
$value = true;
129+
} elseif ($value === 'false') {
130+
$value = false;
131+
}
132+
133+
return $value;
126134
}
127135

128136
private function set($key, $value)
129137
{
130-
Env::getRepository()->set($key, $value);
138+
// Env::getRepository() is immutable but will use values from $_SERVER and $_ENV
139+
$_SERVER[$key] = $value;
140+
$_ENV[$key] = $value;
131141
}
132142

133143
private function decrypt($value)

0 commit comments

Comments
 (0)