Создает ли приложение actix_web App :: register_data один экземпляр или по одному экземпляру на поток?

Я пытаюсь настроить глобальное состояние для своего actix_web::HttpServer, и похоже, что register_data - правильный API (я могу ошибаться).

Из документации непонятно мне, как создать единый экземпляр данных приложения, совместно используемых всеми HttpServer потоками. Вот мой фрагмент кода:

HttpServer::new(|| {
    App::new()
        .register_data(web::Data::new(Mutex::new(MyServer::new())))
        .service(web::resource("/myservice").route(web::post().to(my_service)))
        .service(web::resource("/list").to(list_service))
})

В обработчике POST my_service я обновляю состояние MyServer, а в обработчике GET list_service он распечатывает состояние.

В то время как my_service успешно сохраняет состояние, list_service печатает только пустой вывод. Как узнать, создал ли HttpServer единственный экземпляр MyServer или нет? Если нет, как я могу гарантировать, что он создаст единственный экземпляр? В документации register_data говорится:

Данные приложения не обязательно должны быть Send или Sync. Внутренне Data тип использует Arc. если ваши данные реализуют Send + Sync черты, вы можете использовать web::Data::new() и избегать двойных Arc.

Меня это смущает. Что должен сделать пользователь, чтобы register_data зарегистрировал единственный экземпляр объекта данных? Используется ли следующая строка в примере из документации создать единственный экземпляр или по одному экземпляру на поток?

.register_data(data.clone())

Я использую actix-web 1.0.9.


person user1783732    schedule 09.12.2019    source источник
comment
Трудно ответить на ваш вопрос, потому что он не включает минимально воспроизводимый пример. Мы не можем сказать, какие ящики (и их версии) присутствуют в коде, и есть несколько отсутствующих реализаций функций. Нам было бы проще помочь вам, если вы попытаетесь воспроизвести свою ошибку на Rust Playground, если возможно, в противном случае в новом проекте Cargo отредактируйте свой вопрос, включив в него дополнительную информацию. Есть советы MRE для Rust, которые вы можете использовать, чтобы сократить исходный код для публикации здесь. Спасибо!   -  person Shepmaster    schedule 09.12.2019
comment
Я отредактировал свой вопрос, чтобы немного уточнить. Постараюсь ввести в него более полный код и поиграть в Rust Playground. Спасибо.   -  person user1783732    schedule 09.12.2019
comment
Я могу остановиться, но без редактирования в соответствии со стандартами нашего сообщества публикация, скорее всего, получит больше голосов против по легко устранимым причинам. Я делаю правку, чтобы упростить людям ответ на вопрос и, чтобы другие люди могли его найти в будущем.   -  person Shepmaster    schedule 10.12.2019


Ответы (1)


После того, как я немного поигрался с кодом Rust, теперь я лучше понимаю. web::Data - это Arc, поэтому можно вызвать data.clone(), который создает новый экземпляр Arc, но по-прежнему указывает на единственный общий экземпляр MyServer. Это позволит HttpServer потокам совместно использовать глобальное состояние.

Итак, чтобы решить свою проблему, я просто последовал примеру из документации, то есть переместил создание данных из HttpServer::new и вызвал clone() внутри него:

    let my_data = web::Data::new(Mutex::new(MyServer::new()));
    HttpServer::new(move || {
        App::new()
            .register_data(my_data.clone())  // only Arc is cloned
            .service(web::resource("/myservice").route(web::post().to(my_service)))
            .service(web::resource("/list").to(list_service))    
    })
person user1783732    schedule 10.12.2019
comment
Кстати, у actix-web::App есть два API для установки данных приложения: register_data и data, что немного сбивает с толку. - person user1783732; 10.12.2019