UNPKG

@datalayer/core

Version:

[![Datalayer](https://assets.datalayer.tech/datalayer-25.svg)](https://datalayer.io)

181 lines (180 loc) 6.56 kB
/* * Copyright (c) 2023-2025 Datalayer, Inc. * Distributed under the terms of the Modified BSD License. */ import { useStore } from 'zustand'; import { createStore } from 'zustand/vanilla'; import { JSONExt } from '@lumino/coreutils'; import { Poll } from '@lumino/polling'; import { getRuntimes } from '../../stateful/runtimes'; import { coreStore } from './CoreState'; import { iamStore } from './IAMState'; /** * Kernel store */ export const runtimesStore = createStore((set, get) => { return { configuration: { maxNotebookRuntimes: 5, maxCellRuntimes: 3, }, setConfiguration: (configuration) => { set(state => JSONExt.deepEqual(state.configuration, configuration) ? {} : { configuration: { ...configuration } }); }, runtimesRunUrl: coreStore.getState().configuration?.runtimesRunUrl, tab: 0.0, getIntTab: () => Math.floor(get().tab), setTab: (tab) => set(state => ({ tab })), /** * Remote runtime pods. */ runtimePods: [], /** * Refresh the runtime pods. */ refreshRuntimePods: async () => { const servers = await getRuntimes(); // Update the state with the Remote Kernels. if (!JSONExt.deepEqual(get().runtimePods, servers)) { set({ runtimePods: [...servers] }); } }, /** * Cached runtime models. */ runtimeModels: [], /** * Add a runtime model */ addRuntimeModel: (model) => { const kernels = get().runtimeModels; // TODO // We need to review the IRuntimeModel/IRuntimePod/Kernel.IModel and their id/uid handling. // The id is the kernel id, which is no more always present for some reasons. // So we need to also check the uid of the model. const index = kernels.findIndex(m => (model.id === m.id || model.uid === m.uid) ?? -1); if (index < 0) { set({ runtimeModels: [...kernels, model] }); } }, /** * Remove a runtime model by ID. */ removeRuntimeModel: (id) => { const kernels = [...get().runtimeModels]; const index = kernels?.findIndex(model => id === model.id) ?? -1; if (index >= 0) { kernels.splice(index, 1); set({ runtimeModels: kernels }); } }, setRuntimeModels: (models) => { if (!JSONExt.deepEqual(get().runtimeModels, models)) { set({ runtimeModels: [...models] }); } }, multiServiceManager: undefined, setMultiServiceManager: multiServiceManager => { set(state => ({ multiServiceManager })); }, showDisclaimer: false, setShowDisclaimer: showDisclaimer => { set(state => ({ showDisclaimer })); }, /** * Kernel Snapshots. */ runtimeSnapshots: [], /** * Add a Kernel Snapshot */ addRuntimeSnapshot: (snapshot) => { const snapshots = get().runtimeSnapshots; const index = snapshots.findIndex(s => s.id === snapshot.id); if (index < 0) { const kernelSnapshots = [...snapshots, snapshot]; set({ runtimeSnapshots: kernelSnapshots }); } else if (!JSONExt.deepEqual(snapshots[index], snapshot)) { const kernelSnapshots = [...snapshots]; kernelSnapshots.splice(index, 1, snapshot); set({ runtimeSnapshots: kernelSnapshots }); } }, /** * Remove a Kernel Snapshot. */ removeRuntimeSnapshot: (id) => { const snapshots = get().runtimeSnapshots; const index = snapshots.findIndex(s => s.id === id); if (index >= 0) { const kernelSnapshots = [...snapshots]; kernelSnapshots.splice(index, 1); set({ runtimeSnapshots: kernelSnapshots }); } }, /** * Set Kernel Snapshots. */ setRuntimeSnapshots: (snapshots) => { if (!JSONExt.deepEqual(get().runtimeSnapshots, snapshots)) { set({ runtimeSnapshots: [...snapshots] }); } }, version: '', setVersion: version => { if (version && !get().version) { set(state => ({ version })); } }, }; }); // Poll remote kernels const kernelsPoll = new Poll({ auto: true, factory: () => runtimesStore.getState().refreshRuntimePods(), frequency: { interval: 61 * 1000, backoff: true, max: 300 * 1000, }, name: '@datalayer/jupyter-kernels:KernelsManager#kernels', standby: () => iamStore.getState().token || runtimesStore.getState().runtimesRunUrl ? 'when-hidden' : true, }); // Force refresh at expiration date if next tick is after it. runtimesStore.subscribe((state, prevState) => { if (!JSONExt.deepEqual(state.runtimePods, prevState.runtimePods)) { const now = Date.now(); const minExpiredAt = Math.min(...state.runtimePods.map(kernel => kernel.expired_at ? parseFloat(kernel.expired_at) : Infinity)) * 1_000; // Refresh 2 sec after the closest expiration time // to let some times to the system to dispose the resources. if (now + kernelsPoll.frequency.interval > minExpiredAt + 2_000) { setTimeout(() => { kernelsPoll.refresh(); }, minExpiredAt + 2_000 - now); } } }); coreStore.subscribe((state, prevState) => { if (state.configuration.runtimesRunUrl && state.configuration.runtimesRunUrl !== prevState.configuration.runtimesRunUrl) { const runtimesRunUrl = state.configuration.runtimesRunUrl; console.log(`Updating runtimesRunUrl with new value ${runtimesRunUrl}`); runtimesStore.setState({ runtimesRunUrl }); kernelsPoll .refresh() .then(() => kernelsPoll.tick) .catch(reason => { console.error('Failed to refresh kernel servers list following service URL changed.', reason); }); } }); export function useRuntimesStore(selector) { return useStore(runtimesStore, selector); } export default useRuntimesStore;