Синхронизировать процессы Windows VSCode

Я работаю над расширением, которое периодически отправляет запросы к HTTP API. Если открыто несколько окон VSCode, похоже, что все они отправляют такие запросы, что не оптимально.

Поэтому я хочу убедиться, что запросы выполняются только в одном месте, например. в одном окне VSCode или глобальном процессе, а затем пересылается в другие окна для обновления древовидного представления.

Как можно осуществить эту синхронизацию?

В VS Code API нет ничего подобного, поэтому, вероятно, вам придется разработать/реализовать его самостоятельно.

Lex Li 10.06.2024 03:46

@LexLi. Это тоже был мой вывод. Но я не уверен, как реализовать эту синхронизацию. Я не нашел много механизмов для отправки сообщений между окнами VSCode. Есть SecretStorage, но он явно не предназначен для синхронизации.

md2perpe 10.06.2024 22:15

@LexLi. Есть ли у вас какие-либо предложения, как это сделать? Какой механизм межпроцессного взаимодействия вы бы использовали?

md2perpe 11.06.2024 17:51

@LexLi. Нет решения? Возможно, это было не так просто, как вы думали?

md2perpe 15.06.2024 20:07

@LexLi. Проблема в том, что большинство коммуникаций, например. WebSockets, это сервер-клиент, но здесь все окна равны. Непонятно, где запускать сервер.

md2perpe 15.06.2024 21:45

Я нашел способ, который может сработать: сохранить данные в файле (в каталоге, заданном context.globalStorageUri()) и использовать fs.watch(), чтобы увидеть, когда они были изменены.

md2perpe 15.06.2024 21:50

@LexLi. Процесс вне VSCode, который все пользователи расширения должны запускать вручную? Или расширение должно запускать его из одного окна VSCode? Все окна затем попытаются запустить процесс.

md2perpe 16.06.2024 10:07

@LexLi. Учитывая, насколько это «тривиально», вы, похоже, неспособны показать мне, как это сделать.

md2perpe 16.06.2024 21:24

Внедрить межпроцессное взаимодействие на основе сети. Если вы запустите vscode/ваше расширение, проверьте, прослушивает ли что-нибудь порт/сокет xyz, если нет, запустите сервер, если порт уже используется, попробуйте подключиться к нему. Или реализовать «файл блокировки». Это не так сложно, как кажется.

Marc 27.06.2024 09:00
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
9
155
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как сказано в моем комментарии, вам необходимо реализовать межпроцессное взаимодействие (IPC).

Самый «простой» способ добиться этого — сетевые сокеты.

  • Начать процесс
  • Проверьте, существует ли файл pid/lockfile
  • N: Запишите куда-нибудь файл pid/lock.
  • Y: Попробуйте подключиться к сетевому сокету
const { createServer, Socket } = require("net");
const fs = require("fs");
const os = require("os");


const LOCKFILE_LOCATION = `${os.tmpdir()}/my-lockfile.pid`;
const HOST = "127.0.0.5";
const PORT = 9317;


console.info("Started...");
console.info("Check fo lockfile %s", LOCKFILE_LOCATION)


if (fs.existsSync(LOCKFILE_LOCATION)) {

    console.info("Lockfile exists, start in client mode");

    let client = new Socket();

    client.once("close", () => {

        console.info("Socket closed");
        let pid = Number(fs.readFileSync(LOCKFILE_LOCATION, "utf-8"));

        setTimeout(() => {
            try {

                // 0 is a special signal that doesnt actually kill the process
                // process.kill will throw a error
                process.kill(pid, 0); 
                
            } catch (error) {
                if (error.code === "ESRCH") {

                    // process is not running
                    // cleanup & exit or swpan new server here
                    fs.rmSync(LOCKFILE_LOCATION);

                    console.info("Lock/pid file removed");

                    // use a random setTimeout/sleep before creating a new server
                    // the main process part below could be outsourced in a function, which you can call here again

                } else if (error.code === "EPERM") {

                    console.info("process is maybe running");

                } else {

                    console.error("Could not check if main process is running", error);

                }
            }
        }, 100);

    });

    client.on("data", (data) => {
        console.info("data from main/server process", data.toString());
    });

    client.connect(PORT, HOST);

} else {

    console.info("Lockfile does not exists, start in server mode");

    // store the PID in the lockfile to check if the process is running on exit
    // if not, delete the lockfile
    fs.writeFileSync(LOCKFILE_LOCATION, `${process.pid}`);

    let server = createServer();

    server.on("connection", (socket) => {

        socket.write(`Hello client, server here ${process.pid}. You want some http requests data?`);

    });

    // 127.0.0.5 used on purpose
    server.listen(PORT, HOST, () => {
        console.info(`Server listening on tcp://${HOST}${PORT}`);
    });

}

Приведенный выше пример не идеален, но является хорошей отправной точкой для понимания концепции.

Например. что происходит, когда основное окно процесса/кода закрыто, но остальные все еще открыты? Затем вы можете создать новый сетевой сокет. Будьте осторожны и не пытайтесь создать несколько сокетов. Чтобы избежать этого, можно использовать случайный сон/setTimeout.

Видите ли, при работе с IPC следует учитывать и другие вещи.

Обновлено: Чтобы лучше показать, как осуществляется синхронизация, я немного изменил приведенный выше код.

    let server = createServer();
    let clients = new Set();

    // this simulates your http/api requests
    // unref is used that the process exits
    setInterval(() => {

        console.info("Broadcast data to %d clients", clients.size);

        let data = JSON.stringify({
            boolean: true,
            timestamp: Date.now(),
            string: "Hello Client"
        });

        Array.from(clients).forEach((socket, i) =>{
            socket.write(data, () => {
                console.info("Data writen to client #%d", i);
            });
        });

    }, 5000).unref();

    server.on("connection", (socket) => {

        console.info("Client connected");

        socket.once("close", () => {

            console.info("Client disconnected");
            clients.delete(socket);

        });

        socket.write(`Hello client, server here ${process.pid}. You want some http requests data?`);
        clients.add(socket);

    });

Вместо setInterval отправляйте туда HTTP-запросы, а когда вы получите необходимые данные, отправьте их через сетевой сокет всем подключенным клиентам.

То есть синхронизация здесь в основном осуществляется с использованием файла (файла блокировки)?

md2perpe 29.06.2024 09:02

Синхронизация сама по себе осуществляется через сетевой сокет. В основном процессе (где создается tcp-сервер) выполняйте запросы HTTP API и отправляйте их всем подключенным клиентам. Это ваша синхронизация. Файл блокировки предназначен только для того, чтобы сообщить другим VS Code Windows, следует ли им запускаться как клиенты и подключаться к серверу или запускать запуск.

Marc 01.07.2024 08:03

@md2perpe Я обновил код, чтобы лучше показать, как можно выполнить синхронизацию.

Marc 01.07.2024 08:28

@md2perpe Есть ли у вас вопросы по коду или понятно, как отправлять данные с сервера (главное окно) клиентам?

Marc 02.07.2024 10:30

Я понимаю, как работает код. Процесс, который первым на шаре, сообщает другим процессам «Я делаю это», создавая файл блокировки, а затем запускает сервер. Затем другие процессы подключаются к серверу, чтобы получить от него данные. Если сервер или процесс, запускающий его, завершает работу или умирает, первый процесс, который это заметит, должен запустить новый сервер. Есть некоторые пробелы, которые могут привести к гонке; если это проблема, следует использовать мьютекс.

md2perpe 02.07.2024 21:03

@md2perpe Если это решение, с которым вы можете работать, отметьте его как таковое.

Marc 03.07.2024 09:50

Другие вопросы по теме

Пытаюсь запустить скрипт в режиме отладки, но получаю сообщение «AssertionError: аргумент группы на данный момент должен быть None»
Как включить раскрывающееся меню командлетов/параметров IntelliSense Powershell в терминале VSCode, как в терминале ISE, с помощью CTRL + пробел?
VS Code and Liberty: источник данных, определенный в server.xml, не найден сервером
VS Code 1.90 PowerShell экранирует escape-коды ANSI, такие как «\x1b[0m»
Терминалу Windows VS Code требуется около 5 секунд, чтобы вернуться в командную строку после нажатия Enter
Можно ли в Visual Studio Code автоматически переключаться на панель «Проблемы», когда при сборке возникают ошибки?
Как открыть диалог фильтра/поиска _inside_ хлебных крошек в VS Code?
VS Code закрывается после открытия
Код Visual Studio аварийно завершает работу, когда чтение [...ERROR:process_memory_range.cc(75)] выходит за пределы диапазона
Прослушивание Xdebug в VSCode не останавливается на точке останова