()
| 164 | * |
| 165 | */ |
| 166 | export function sessionConsistency() { |
| 167 | return Prisma.defineExtension((client) => |
| 168 | client.$extends({ |
| 169 | name: 'session-consistency', |
| 170 | query: { |
| 171 | $allOperations: async ({ |
| 172 | operation, |
| 173 | model, |
| 174 | args, |
| 175 | query, |
| 176 | // This is a hack to force reads to primary when replica hasn't caught up. |
| 177 | // The readReplicas extension routes queries to primary when in a transaction, |
| 178 | // so we set __internalParams.transaction = true to achieve this. |
| 179 | // @ts-expect-error - __internalParams is not in the types |
| 180 | __internalParams, |
| 181 | }) => { |
| 182 | const sessionId = getAlsSessionId(); |
| 183 | |
| 184 | // For write operations with session: cache WAL LSN after write |
| 185 | if (isWriteOperation(operation)) { |
| 186 | // logger.info('Prisma operation', { |
| 187 | // operation, |
| 188 | // args, |
| 189 | // model, |
| 190 | // }); |
| 191 | |
| 192 | const result = await query(args); |
| 193 | |
| 194 | if (sessionId) { |
| 195 | // Get current WAL LSN and cache it for this session |
| 196 | const lsn = await getCurrentWalLsn(client); |
| 197 | if (lsn) { |
| 198 | await cacheWalLsnForSession(sessionId, lsn); |
| 199 | logger.debug( |
| 200 | { sessionId, lsn, operation, model }, |
| 201 | 'Cached WAL LSN after write', |
| 202 | ); |
| 203 | } |
| 204 | } |
| 205 | |
| 206 | return result; |
| 207 | } |
| 208 | |
| 209 | // For now, we just force the read to the primary without checking the replica |
| 210 | // Since the check probably goes to the primary anyways it will always be true, |
| 211 | // Not sure how to check LSN on the actual replica that will be used for the read. |
| 212 | if ( |
| 213 | model !== 'Session' && |
| 214 | isReadOperation(operation) && |
| 215 | sessionId && |
| 216 | (await getCachedWalLsn(sessionId)) |
| 217 | ) { |
| 218 | const MAX_RETRIES = 3; |
| 219 | const INITIAL_RETRY_DELAY_MS = 50; |
| 220 | |
| 221 | for (let attempt = 0; attempt < MAX_RETRIES; attempt++) { |
| 222 | const result = await query(args); |
| 223 |
nothing calls this directly
no test coverage detected