fix(search): scope failure locks so search cannot take chat offline
Two problems on the credentialFallback path, where a search provider borrows a chat provider's connection: - the lock was attributed to the search provider id, but the connection belongs to the chat provider, so markAccountUnavailable looked it up under the wrong provider and read a stale backoffLevel - with no model argument the lock key is `modelLock___all`, which isModelLockActive treats as blocking every model — one failing search would have taken the shared glm key offline for chat as well Attribute the lock to the provider that owns the connection, and scope it to `websearch:<provider>`, passed to getProviderCredentials too so the lock is read back under the same key.
This commit is contained in:
@@ -154,14 +154,24 @@ async function handleSingleProviderSearch(body, providerInput, request, apiKey,
|
||||
// fall back to the linked provider's credentials.
|
||||
const fallbackProviderId = resolvedProvider.credentialFallback;
|
||||
|
||||
// Lock scope for this handler. Without it markAccountUnavailable would write
|
||||
// an account-wide `__all` lock, which on the credentialFallback path takes
|
||||
// the shared chat key (e.g. glm) offline for chat as well. Must be passed to
|
||||
// getProviderCredentials too, so the lock is read back under the same key.
|
||||
const searchLockKey = `websearch:${providerId}`;
|
||||
|
||||
while (true) {
|
||||
let credentials = await getProviderCredentials(providerId, excludeConnectionIds);
|
||||
// Provider that actually owns the connection in use — differs from
|
||||
// providerId once we fall back, and error locks must be attributed to it.
|
||||
let credentialProviderId = providerId;
|
||||
let credentials = await getProviderCredentials(providerId, excludeConnectionIds, searchLockKey);
|
||||
|
||||
// Fall back to the related chat provider's credentials when this search
|
||||
// provider has none of its own (one key, chat + search).
|
||||
if (!credentials && fallbackProviderId) {
|
||||
credentials = await getProviderCredentials(fallbackProviderId, excludeConnectionIds);
|
||||
credentials = await getProviderCredentials(fallbackProviderId, excludeConnectionIds, searchLockKey);
|
||||
if (credentials) {
|
||||
credentialProviderId = fallbackProviderId;
|
||||
log.info("AUTH", `\x1b[32m${providerId} reusing ${fallbackProviderId} credentials\x1b[0m`);
|
||||
}
|
||||
}
|
||||
@@ -206,7 +216,7 @@ async function handleSingleProviderSearch(body, providerInput, request, apiKey,
|
||||
|
||||
if (result.success) return result.response;
|
||||
|
||||
const { shouldFallback } = await markAccountUnavailable(credentials.connectionId, result.status, result.error, providerId);
|
||||
const { shouldFallback } = await markAccountUnavailable(credentials.connectionId, result.status, result.error, credentialProviderId, searchLockKey);
|
||||
|
||||
if (shouldFallback) {
|
||||
log.warn("AUTH", `Account ${credentials.connectionName} unavailable (${result.status}), trying fallback`);
|
||||
|
||||
Reference in New Issue
Block a user