Skip to content
This repository has been archived by the owner on Oct 18, 2021. It is now read-only.

Result::unwrap() called on Err when no server is available #135

Closed
w-k-s opened this issue Feb 5, 2016 · 3 comments
Closed

Result::unwrap() called on Err when no server is available #135

w-k-s opened this issue Feb 5, 2016 · 3 comments

Comments

@w-k-s
Copy link

w-k-s commented Feb 5, 2016

Hi guys,

I'm writing a REST api using the Nickel framework and your (Excellent!) Mongo driver library.
The REST api will be consumed by a mobile application and, in order to provide a stable backend, I'm making sure that all errors return a meaningful message.

To that end, I'm handling the scenario where a connection to mongodb is unavailable in the GET /users request (line 44-50):

#[macro_use] 
extern crate nickel;

extern crate rustc_serialize;

#[macro_use(bson, doc)]
extern crate bson;
extern crate mongodb;

// Nickel
use nickel::{Nickel, JsonBody, HttpRouter, MediaType};
use nickel::status::StatusCode::{self};

// MongoDB
use mongodb::{Client, ThreadedClient};
use mongodb::db::ThreadedDatabase;

// bson
use bson::{Bson};

// rustc_serialize
use rustc_serialize::json::{self,Json, ToJson};

#[derive(RustcDecodable, RustcEncodable)]
struct ApiResponse<T>{
    data: T
}

#[derive(RustcDecodable, RustcEncodable)]
struct ApiError{
    error: String
}


fn main() {

    let mut server = Nickel::new();
    let mut router = Nickel::router();

    router.get("/users",middleware!(|request,mut response|{

        response.set(MediaType::Json);

        let client = match Client::connect("127.0.0.1",27017){
            Ok(c)=> c,
            Err(e)=>{
                //EXPECTED OUTCOME
                response.set(StatusCode::InternalServerError);
                return response.send(json::encode(&ApiError{error: format!("{}",e)}).unwrap());
            }
        };

        let collection = client.db("rust-users").collection("users");

        let mut json_users : Vec<Json> = vec![];
        let mut cursor = collection.find(None, None).unwrap();

        for result in cursor{
            match result {
                Ok(doc)=>{
                    let json_user = Bson::Document(doc).to_json();
                    json_users.push(json_user)
                },
                Err(_)=>continue,
            }
        }

        (StatusCode::Ok,json::encode(&ApiResponse{data: json_users}).unwrap())

    }));

    server.utilize(router);
    server.listen("127.0.0.1:6767");
}

In order to test this, I deactivated the mongodb server and sent a GET request.
The application panicked producing the following message:

thread '' panicked at 'called Result::unwrap() on an Err value: OperationError("No servers available for the provided ReadPreference.")', ../src/libcore/result.rs:741

I do not believe this is correct behavior. The error should propagate up to the final result where I can handle it according to my needs.

@saghm
Copy link
Contributor

saghm commented Feb 5, 2016

From running this code on my own machine, it appears that the unwrapping actually occurs in your own code on line 56, namely let mut cursor = collection.find(None, None).unwrap(); You can verify this by using gdb to run the actual binary file generated in the target subdirectory and setting a breakpoint at rust_panic.

One thing that's a bit subtle about Client::connect is that the errors tht it returns actually have to do with properly initializing the mutex and with creating the topology. You can look at Client::with_config (which is called by Client::connect to see the details of this.

On a slightly unrelated note, creating a new Client on every request is fairly inefficient. Client is actually just an alias of an Arc type, which means you can open the connection at the top of the function and then just use .clone() to get an (owned) atomic reference to it inside each of your routes that need it.

@w-k-s
Copy link
Author

w-k-s commented Feb 5, 2016

Thank you so much for such an informative response.
I had an uneasy feeling about creating multiple clients; I was mislead by a tutorial. Thanks for setting me straight
And I hadn't played with the debugger before posting this ticket. I see that it is indeed a fault of my own!

@w-k-s w-k-s closed this as completed Feb 5, 2016
@vkarpov15
Copy link
Contributor

Thanks @saghm

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants