Passed
Pull Request — main (#3)
by
unknown
02:49
created

insertInvalidationEvent()   B

Complexity

Conditions 8
Paths 36

Size

Total Lines 57
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 8
eloc 35
c 2
b 0
f 0
nc 36
nop 7
dl 0
loc 57
rs 8.1155

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Padosoft\SuperCacheInvalidate\Helpers;
4
5
use Illuminate\Support\Facades\DB;
6
use Illuminate\Support\Facades\Log;
7
use Illuminate\Support\Facades\Redis;
8
9
class SuperCacheInvalidationHelper
10
{
11
    /**
12
     * Insert a cache invalidation event into the database.
13
     *
14
     * @param string      $type                  'key' or 'tag'
15
     * @param string      $identifier            The cache key or tag to invalidate
16
     * @param string|null $connection_name       The Redis Connection name (optional, 'default')
17
     * @param string|null $reason                Reason for invalidation (optional)
18
     * @param int|null    $totalShards           Total number of shards (from config if null)
19
     * @param int|null    $priority              Priority of the event
20
     * @param array|null  $associatedIdentifiers Optional array of associated tags or keys
21
     */
22
    public function insertInvalidationEvent(
23
        string $type,
24
        string $identifier,
25
        ?string $connection_name = null,
26
        ?string $reason = null,
27
        ?int $totalShards = 0,
28
        ?int $priority = 0,
29
        ?array $associatedIdentifiers = [],
30
    ): void {
31
        $shard = crc32($identifier) % ($totalShards > 0 ? $totalShards : config('super_cache_invalidate.total_shards', 10));
32
33
        $redisConnectionName = $connection_name ?? config('super_cache_invalidate.default_connection_name');
34
        $data = [
35
            'type' => $type,
36
            'identifier' => $identifier,
37
            'connection_name' => $redisConnectionName,
38
            'reason' => $reason,
39
            'priority' => $priority,
40
            'event_time' => now(),
41
            'processed' => 0,
42
            'shard' => $shard,
43
        ];
44
45
        $maxAttempts = 5;
46
        $attempts = 0;
47
        $insertOk = false;
48
49
        while ($attempts < $maxAttempts && !$insertOk) {
50
            DB::beginTransaction();
51
52
            try {
53
                // Cerca di bloccare il record per l'inserimento
54
                $eventId = DB::table('cache_invalidation_events')->insertGetId($data);
55
56
                // Insert associated identifiers
57
                if (!empty($associatedIdentifiers)) {
58
                    $associations = [];
59
                    foreach ($associatedIdentifiers as $associated) {
60
                        $associations[] = [
61
                            'event_id' => $eventId,
62
                            'associated_type' => $associated['type'], // 'key' or 'tag'
63
                            'associated_identifier' => $associated['identifier'],
64
                            'connection_name' => $associated['connection_name'],
65
                            'created_at' => now(),
66
                        ];
67
                    }
68
                    DB::table('cache_invalidation_event_associations')->insert($associations);
69
                }
70
                $insertOk = true;
71
                DB::commit(); // Completa la transazione
72
            } catch (\Throwable $e) {
73
                DB::rollBack(); // Annulla la transazione in caso di errore
74
                $attempts++;
75
                // Logica per gestire i tentativi falliti
76
                if ($attempts >= $maxAttempts) {
77
                    // Salta il record dopo il numero massimo di tentativi
78
                    Log::error("SuperCacheInvalidate: impossibile eseguire insert dopo $maxAttempts tentativi: " . $e->getMessage());
79
                }
80
            }
81
        }
82
    }
83
84
    /**
85
     * Acquire a lock for processing a shard.
86
     *
87
     * @param  int          $shardId         The shard number
88
     * @param  int          $lockTimeout     Lock timeout in seconds
89
     * @param  string       $connection_name The Redis Connection name
90
     * @return string|false The lock value if acquired, false otherwise
91
     */
92
    public function acquireShardLock(int $shardId, int $priority, int $lockTimeout, string $connection_name): bool|string
93
    {
94
        $lockKey = 'shard_lock:' . $shardId . '_' . $priority;
95
        // Il metodo has/exists occupa troppa memoria!!!
96
        $retrieveValue = Redis::connection($connection_name)->get($lockKey);
97
        if ($retrieveValue !== null) {
98
            // Lock già attivo
99
            return false;
100
        }
101
        $lockValue = uniqid('', true);
102
        $isLocked = Redis::connection($connection_name)->set($lockKey, $lockValue);
103
104
        if ($lockTimeout > 0) {
105
            Redis::connection($connection_name)->expire($lockKey, $lockTimeout);
106
        }
107
108
        return $isLocked ? $lockValue : false;
109
    }
110
111
    /**
112
     * Release the lock for a shard.
113
     *
114
     * @param int    $shardId         The shard number
115
     * @param string $lockValue       The lock value to validate ownership
116
     * @param string $connection_name The Redis Connection name
117
     */
118
    public function releaseShardLock(int $shardId, int $priority, string $lockValue, string $connection_name): void
119
    {
120
        $lockKey = 'shard_lock:' . $shardId . '_' . $priority;
121
        $currentValue = Redis::connection($connection_name)->get($lockKey);
122
        if ($currentValue === $lockValue) {
123
            Redis::connection($connection_name)->del($lockKey);
124
        }
125
    }
126
}
127