mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-29 10:42:44 +00:00
put search provider global state in store
This commit is contained in:
@@ -1,33 +1,19 @@
|
|||||||
import { ref } from 'vue'
|
|
||||||
|
|
||||||
import { useAlgoliaSearchProvider } from '@/services/providers/algoliaSearchProvider'
|
import { useAlgoliaSearchProvider } from '@/services/providers/algoliaSearchProvider'
|
||||||
import { useComfyRegistrySearchProvider } from '@/services/providers/registrySearchProvider'
|
import { useComfyRegistrySearchProvider } from '@/services/providers/registrySearchProvider'
|
||||||
|
import { useComfyRegistryStore } from '@/stores/comfyRegistryStore'
|
||||||
import type { SearchNodePacksParams } from '@/types/algoliaTypes'
|
import type { SearchNodePacksParams } from '@/types/algoliaTypes'
|
||||||
import type { components } from '@/types/comfyRegistryTypes'
|
import type { components } from '@/types/comfyRegistryTypes'
|
||||||
import type {
|
import type {
|
||||||
NodePackSearchProvider,
|
NodePackSearchProvider,
|
||||||
|
ProviderState,
|
||||||
SearchPacksResult
|
SearchPacksResult
|
||||||
} from '@/types/searchServiceTypes'
|
} from '@/types/searchServiceTypes'
|
||||||
|
|
||||||
type RegistryNodePack = components['schemas']['Node']
|
type RegistryNodePack = components['schemas']['Node']
|
||||||
|
|
||||||
interface ProviderState {
|
|
||||||
provider: NodePackSearchProvider
|
|
||||||
name: string
|
|
||||||
isHealthy: boolean
|
|
||||||
lastError?: Error
|
|
||||||
lastAttempt?: Date
|
|
||||||
consecutiveFailures: number
|
|
||||||
}
|
|
||||||
|
|
||||||
const CIRCUIT_BREAKER_THRESHOLD = 3 // Number of failures before circuit opens
|
const CIRCUIT_BREAKER_THRESHOLD = 3 // Number of failures before circuit opens
|
||||||
const CIRCUIT_BREAKER_TIMEOUT = 60000 // 1 minute before retry
|
const CIRCUIT_BREAKER_TIMEOUT = 60000 // 1 minute before retry
|
||||||
|
|
||||||
// Global state shared across all uses of the gateway
|
|
||||||
const providers: ProviderState[] = []
|
|
||||||
const activeProviderIndex = ref(0)
|
|
||||||
let isInitialized = false
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API Gateway for registry search providers with circuit breaker pattern.
|
* API Gateway for registry search providers with circuit breaker pattern.
|
||||||
* Acts as a single entry point that routes search requests to appropriate providers
|
* Acts as a single entry point that routes search requests to appropriate providers
|
||||||
@@ -39,11 +25,13 @@ let isInitialized = false
|
|||||||
* - Automatic failover: Cascades through providers on failure
|
* - Automatic failover: Cascades through providers on failure
|
||||||
*/
|
*/
|
||||||
export const useRegistrySearchGateway = (): NodePackSearchProvider => {
|
export const useRegistrySearchGateway = (): NodePackSearchProvider => {
|
||||||
|
const store = useComfyRegistryStore()
|
||||||
|
|
||||||
// Initialize providers only once
|
// Initialize providers only once
|
||||||
if (!isInitialized) {
|
if (!store.isSearchGatewayInitialized) {
|
||||||
// Initialize providers in priority order
|
// Initialize providers in priority order
|
||||||
try {
|
try {
|
||||||
providers.push({
|
store.searchProviders.push({
|
||||||
provider: useAlgoliaSearchProvider(),
|
provider: useAlgoliaSearchProvider(),
|
||||||
name: 'Algolia',
|
name: 'Algolia',
|
||||||
isHealthy: true,
|
isHealthy: true,
|
||||||
@@ -53,14 +41,14 @@ export const useRegistrySearchGateway = (): NodePackSearchProvider => {
|
|||||||
console.warn('Failed to initialize Algolia provider:', error)
|
console.warn('Failed to initialize Algolia provider:', error)
|
||||||
}
|
}
|
||||||
|
|
||||||
providers.push({
|
store.searchProviders.push({
|
||||||
provider: useComfyRegistrySearchProvider(),
|
provider: useComfyRegistrySearchProvider(),
|
||||||
name: 'ComfyRegistry',
|
name: 'ComfyRegistry',
|
||||||
isHealthy: true,
|
isHealthy: true,
|
||||||
consecutiveFailures: 0
|
consecutiveFailures: 0
|
||||||
})
|
})
|
||||||
|
|
||||||
isInitialized = true
|
store.isSearchGatewayInitialized = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add an "offline" provider that operates on a local cache of the registry.
|
// TODO: Add an "offline" provider that operates on a local cache of the registry.
|
||||||
@@ -118,16 +106,17 @@ export const useRegistrySearchGateway = (): NodePackSearchProvider => {
|
|||||||
*/
|
*/
|
||||||
const getActiveProvider = (): NodePackSearchProvider => {
|
const getActiveProvider = (): NodePackSearchProvider => {
|
||||||
// First, try to use the current active provider if it's healthy
|
// First, try to use the current active provider if it's healthy
|
||||||
const currentProvider = providers[activeProviderIndex.value]
|
const currentProvider =
|
||||||
|
store.searchProviders[store.activeSearchProviderIndex]
|
||||||
if (currentProvider && isCircuitClosed(currentProvider)) {
|
if (currentProvider && isCircuitClosed(currentProvider)) {
|
||||||
return currentProvider.provider
|
return currentProvider.provider
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, find the first healthy provider
|
// Otherwise, find the first healthy provider
|
||||||
for (let i = 0; i < providers.length; i++) {
|
for (let i = 0; i < store.searchProviders.length; i++) {
|
||||||
const providerState = providers[i]
|
const providerState = store.searchProviders[i]
|
||||||
if (isCircuitClosed(providerState)) {
|
if (isCircuitClosed(providerState)) {
|
||||||
activeProviderIndex.value = i
|
store.activeSearchProviderIndex = i
|
||||||
return providerState.provider
|
return providerState.provider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,8 +129,8 @@ export const useRegistrySearchGateway = (): NodePackSearchProvider => {
|
|||||||
* Move to the next provider if available.
|
* Move to the next provider if available.
|
||||||
*/
|
*/
|
||||||
const updateActiveProviderOnFailure = () => {
|
const updateActiveProviderOnFailure = () => {
|
||||||
if (activeProviderIndex.value < providers.length - 1) {
|
if (store.activeSearchProviderIndex < store.searchProviders.length - 1) {
|
||||||
activeProviderIndex.value++
|
store.activeSearchProviderIndex++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,17 +144,23 @@ export const useRegistrySearchGateway = (): NodePackSearchProvider => {
|
|||||||
let lastError: Error | null = null
|
let lastError: Error | null = null
|
||||||
|
|
||||||
// Start with the current active provider
|
// Start with the current active provider
|
||||||
for (let attempts = 0; attempts < providers.length; attempts++) {
|
for (
|
||||||
|
let attempts = 0;
|
||||||
|
attempts < store.searchProviders.length;
|
||||||
|
attempts++
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const provider = getActiveProvider()
|
const provider = getActiveProvider()
|
||||||
const providerState = providers[activeProviderIndex.value]
|
const providerState =
|
||||||
|
store.searchProviders[store.activeSearchProviderIndex]
|
||||||
|
|
||||||
const result = await provider.searchPacks(query, params)
|
const result = await provider.searchPacks(query, params)
|
||||||
recordSuccess(providerState)
|
recordSuccess(providerState)
|
||||||
return result
|
return result
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
lastError = error as Error
|
lastError = error as Error
|
||||||
const providerState = providers[activeProviderIndex.value]
|
const providerState =
|
||||||
|
store.searchProviders[store.activeSearchProviderIndex]
|
||||||
recordFailure(providerState, lastError)
|
recordFailure(providerState, lastError)
|
||||||
console.warn(
|
console.warn(
|
||||||
`${providerState.name} search provider failed (${providerState.consecutiveFailures} failures):`,
|
`${providerState.name} search provider failed (${providerState.consecutiveFailures} failures):`,
|
||||||
@@ -187,7 +182,7 @@ export const useRegistrySearchGateway = (): NodePackSearchProvider => {
|
|||||||
* Clear the search cache for all providers that implement it.
|
* Clear the search cache for all providers that implement it.
|
||||||
*/
|
*/
|
||||||
const clearSearchCache = () => {
|
const clearSearchCache = () => {
|
||||||
for (const providerState of providers) {
|
for (const providerState of store.searchProviders) {
|
||||||
try {
|
try {
|
||||||
providerState.provider.clearSearchCache()
|
providerState.provider.clearSearchCache()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -229,11 +224,8 @@ export const useRegistrySearchGateway = (): NodePackSearchProvider => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the filterable fields for the active provider.
|
* Get the filterable fields for the active provider.
|
||||||
* This is now a computed property that will react to provider changes.
|
|
||||||
*/
|
*/
|
||||||
const getFilterableFields = () => {
|
const getFilterableFields = () => {
|
||||||
// Access activeProviderIndex.value to establish reactivity
|
|
||||||
void activeProviderIndex.value
|
|
||||||
const provider = getActiveProvider()
|
const provider = getActiveProvider()
|
||||||
return provider.getFilterableFields()
|
return provider.getFilterableFields()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import QuickLRU from '@alloc/quick-lru'
|
import QuickLRU from '@alloc/quick-lru'
|
||||||
import { partition } from 'lodash'
|
import { partition } from 'lodash'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
import { useCachedRequest } from '@/composables/useCachedRequest'
|
import { useCachedRequest } from '@/composables/useCachedRequest'
|
||||||
import { useComfyRegistryService } from '@/services/comfyRegistryService'
|
import { useComfyRegistryService } from '@/services/comfyRegistryService'
|
||||||
import type { components, operations } from '@/types/comfyRegistryTypes'
|
import type { components, operations } from '@/types/comfyRegistryTypes'
|
||||||
|
import type { ProviderState } from '@/types/searchServiceTypes'
|
||||||
|
|
||||||
const PACK_LIST_CACHE_SIZE = 20
|
const PACK_LIST_CACHE_SIZE = 20
|
||||||
const PACK_BY_ID_CACHE_SIZE = 64
|
const PACK_BY_ID_CACHE_SIZE = 64
|
||||||
@@ -34,6 +36,11 @@ export const useComfyRegistryStore = defineStore('comfyRegistry', () => {
|
|||||||
maxSize: PACK_BY_ID_CACHE_SIZE
|
maxSize: PACK_BY_ID_CACHE_SIZE
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Search gateway state
|
||||||
|
const searchProviders = ref<ProviderState[]>([])
|
||||||
|
const activeSearchProviderIndex = ref(0)
|
||||||
|
const isSearchGatewayInitialized = ref(false)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of all node packs from the registry
|
* Get a list of all node packs from the registry
|
||||||
*/
|
*/
|
||||||
@@ -137,6 +144,11 @@ export const useComfyRegistryStore = defineStore('comfyRegistry', () => {
|
|||||||
cancelRequests,
|
cancelRequests,
|
||||||
|
|
||||||
isLoading: registryService.isLoading,
|
isLoading: registryService.isLoading,
|
||||||
error: registryService.error
|
error: registryService.error,
|
||||||
|
|
||||||
|
// Search gateway state
|
||||||
|
searchProviders,
|
||||||
|
activeSearchProviderIndex,
|
||||||
|
isSearchGatewayInitialized
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -70,3 +70,15 @@ export interface NodePackSearchProvider {
|
|||||||
*/
|
*/
|
||||||
getFilterableFields(): SearchFilter[]
|
getFilterableFields(): SearchFilter[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State of a search provider
|
||||||
|
*/
|
||||||
|
export interface ProviderState {
|
||||||
|
provider: NodePackSearchProvider
|
||||||
|
name: string
|
||||||
|
isHealthy: boolean
|
||||||
|
lastError?: Error
|
||||||
|
lastAttempt?: Date
|
||||||
|
consecutiveFailures: number
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user