Під час розробки програмного забезпечення на мові програмування Rust можуть виникати різні виклики, зокрема пов’язані з надсиланням фьючерів між потоками. У цій статті розглянемо один із таких випадків, коли фьючер, створений асинхронним блоком, не є Send
, що призводить до помилки в Rust API.
Помилка, яка виникає, має наступний вигляд:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
error: future cannot be sent between threads safely --> src/bin/server/server.rs:115:5 | 115 | / { 116 | | info!("identity_create_post({:?}) - X-Span-ID: {:?}", id_create_request, context.get().0.clone()); 117 | | let did: String = match id::create_identity(format!("./{}.hodl", id_create_request.user_id.unwrap()).as_str(), id_create_request.stronghold_password.unwrap().as_str()).await { 118 | | Ok(did) => did, ... | 121 | | Ok(IdentityCreatePostResponse::TheIdentityHasBeenCreatedSuccessfully(models::IdCreateResponse{did:Some(did)}))) 122 | | } | |_____^ future created by async block is not `Send` | = help: the trait `std::marker::Send` is not implemented for `dyn futures::Future<Output = Result<std::string::String, JwkStorageDocumentError>>` note: future is not `Send` as it awaits another future which is not `Send` --> src/bin/server/id.rs:49:26 | 49 | let fragment = match document | __________________________^ 50 | | .generate_method( 51 | | &storage, 52 | | KeyType::from_static_str("Ed25519"), ... | 55 | | MethodScope::VerificationMethod, 56 | | ).await { | |_____^ await occurs here on type `Pin<Box<dyn futures::Future<Output = Result<std::string::String, JwkStorageDocumentError>>>>`, which is not `Send` = note: required for the cast from `Pin<Box<{async block@src/bin/server/server.rs:115:5: 122:6}>>` to `Pin<Box<dyn futures::Future<Output = Result<IdentityCreatePostResponse, ApiError>> + std::marker::Send>> |
Помилка вказує на те, що фьючер, створений асинхронним блоком, не є Send
, що необхідно для безпечного надсилання між потоками. У наданому віріанті коду Rust API проблема виникає через очікування фьючера в середині функції, яка не реалізує Send
.
Проблемний фрагмент коду виглядає наступним чином:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
let fragment = match document .generate_method( &storage, KeyType::from_static_str("Ed25519"), JwsAlgorithm::EdDSA, None, MethodScope::VerificationMethod, ).await { Ok(fragment) => fragment, Err(_) => panic!(), }; println!("-----------------------------\n{:?}",document); drop(fragment); |
Функція generate_method
повертає фьючер, який не є Send
, що призводить до помилки. Оскільки цю функцію змінити неможливо, рішенням є упакування результату для забезпечення Send
.
Для вирішення цієї проблеми можна використати наступний підхід:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
let fragment = match Box::pin(document .generate_method( &storage, KeyType::from_static_str("Ed25519"), JwsAlgorithm::EdDSA, None, MethodScope::VerificationMethod, )).await { Ok(fragment) => fragment, Err(_) => panic!(), }; println!("-----------------------------\n{:?}",document); drop(fragment); |
Упаковка фьючера за допомогою Box::pin
гарантує, що фьючер є Send
, що вирішує проблему в Rust API.