skip to Main Content

I am building a Java Azure Function that I want to connect to my Cosmos DB and perform CRUD Operations within. No matter what I do at the moment, I am unable to connect to the DB when running the function. If I try to do it using @CosmosDBOutput and Document, I am able to upload to the DB, but I need to separate out the functions. Here is my main Handler (that works and uploads using @CosmosDBOutput and Document):

import java.util.*;
import com.microsoft.azure.functions.annotation.*;
import com.microsoft.azure.functions.*;
import com.microsoft.azure.documentdb.Document;

public class Handler {

    @FunctionName("HttpHandler")
    public HttpResponseMessage runHttp(
            @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS)
            HttpRequestMessage<Optional<String>> req, 
            @CosmosDBOutput(name = "database", databaseName = "hyperscalerapi-cosmos-dev", 
            collectionName = "Items", connectionStringSetting = "cosmosDBConnectionString")
            OutputBinding<String> outputItem, final ExecutionContext context) {
        try {
            
            // request to String (payload)
            String payload = req.getBody().get();

            Document document = new Document(payload);
            document.setId(context.getInvocationId().toString());
            outputItem.setValue(document.toString());
            context.getLogger().info("nAdded payload: " + payload + 
                                    "nWith ID: " + context.getInvocationId().toString() + "nTo CosmosDBn");
            
            return req.createResponseBuilder(HttpStatus.OK).body("Data logged").build();
        } catch (Exception e) {
            // log the exception
            context.getLogger().severe(e.toString());
            return req.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR).body("An error occurred").build();
        }
    }
}

The code that I am trying to do is below. This includes the handler as well as my CosmosOperation.java class which I am trying to use to connect to the database:

import java.util.*;
import com.microsoft.azure.functions.annotation.*;
import com.microsoft.azure.functions.*;
import com.microsoft.azure.documentdb.Document;

public class Handler {

    @FunctionName("HttpHandler")
    public HttpResponseMessage runHttp(
            @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS)
            HttpRequestMessage<Optional<String>> req, final ExecutionContext context) {
        try {
            
            // request to String (payload)
            String payload = req.getBody().get();

            // Create in Cosmos
            CosmosOperation p = new CosmosOperation();
            p.create(payload, context);

            return req.createResponseBuilder(HttpStatus.OK).body("Data logged").build();
        } catch (Exception e) {
            // log the exception
            context.getLogger().severe(e.toString());
            return req.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR).body("An error occurred").build();
        }
    }
}

And the CosmosOperation.java class:

    import com.microsoft.azure.functions.annotation.*;
    import com.microsoft.azure.functions.*;
    import java.util.*;
    import java.util.logging.*;
    import com.azure.cosmos.*;
    import com.azure.cosmos.models.*;
    import com.azure.cosmos.util.CosmosPagedIterable;
    import com.microsoft.azure.documentdb.Document;
    //import com.azure.cosmos.examples.common.AccountSettings;
    
    /**
     * Azure Functions in Java with Cosmos DB Trigger.
     */
    public class CosmosOperation {
        public CosmosClient client;
        private final String databaseName = "hyperscalerapi-cosmos-dev";
        private CosmosDatabase database;
        public CosmosContainer container;
        private final String containerName = "Items";
    
        public CosmosOperation() {
            try {
                client = new CosmosClientBuilder()
                            .endpoint("This is where my CosmosDB endpoint is")
                            .key("This is where my CosmosDB Primary Key is")
                            .consistencyLevel(ConsistencyLevel.EVENTUAL)
                            .contentResponseOnWriteEnabled(true)
                            .buildClient();
            } catch (Exception e) {
                System.out.println("----------------------------------------------------------");
                System.out.println(e);
                System.out.println("----------------------------------------------------------");
            }
        }
    public void create(String payload, final ExecutionContext context) {
        container.createItem(payload, new PartitionKey(context.getInvocationId().toString()), new CosmosItemRequestOptions());
    }
}

This is the main error that I am getting. I know that the endpoint and key are correct because they are both in the connection string that I use in my working handler:

java.lang.RuntimeException: Client initialization failed. Check if the endpoint is reachable and if your auth token is valid. More info: https://aka.ms/cosmosdb-tsg-service-unavailable-java

However, I also receive a few of these errors, but I do not think they are important at the moment:

java.lang.NoSuchMethodError: 'void io.netty.handler.codec.http.HttpClientCodec.<init>(int, int, int, boolean, boolean, int, boolean, boolean)'

2

Answers


  1. Below are the observations from the code you shared for CosmosOperation.java class, which is responsible for connecting your code to Cosmos DB and create an item/document.

    1. Assuming that the database hyperscalerapi-cosmos-dev and container Items already created in Cosmos DB account.
    2. To create item/document into respective container we use CreateItem() of CosmosContainer class. You have used the same but have not initialized the container object.
      To initialize container object of CosmosContainer class you can refer below sample code.

    CosmosDatabase db = client.getDatabase("hyperscalerapi-cosmos-dev"); CosmosContainer customContainer = db.getContainer("Items");

    You can refer document.

    Below is sample code I have tried to connect to Cosmos DB:

            CosmosClient client;
            final String databaseName = "hyperscalerapi-cosmos-dev";
            CosmosDatabase database;
            final String containerName = "Items";
            try {
                client = new CosmosClientBuilder()       
                .endpoint("Cosmos DB endpoint")  
                .key("Cosmos DB primary key")
                .consistencyLevel(ConsistencyLevel.EVENTUAL)
                .contentResponseOnWriteEnabled(true)
                .buildClient();
                //get database id or initialize the CosmosDatabase object
                CosmosDatabase db =  client.getDatabase("hyperscalerapi-cosmos-dev");
                //initialization of the CosmosDatabase object
                CosmosContainer container = db.getContainer("Items");
                //Sample class used to create item in Cosmos DB
                Product p = new Product();
                p.setId("4");
                p.setName("ProductName4");
                p.setCategory("Category2");
                container.createItem(p,new PartitionKey(p.getCategory()),new CosmosItemRequestOptions());
            } catch (Exception e) {
                System.out.println("----------------------------------------------------------");
                System.out.println(e);
                System.out.println("----------------------------------------------------------");
            }
    

    Sample class Product.java

    class Product  {  
    String id;  
    String name;  
    String category;  
    public String getId() {  
        return id;  
        }
    public void setId(String id) {  
        this.id = id;  
        }
    public String getName() {  
        return name;
        }
    public void setName(String name) {  
        this.name = name;
        } 
    public String getCategory() {  
        return category;  
        }  
    public void setCategory(String category) {  
        this.category = category;  
        }  
     }
    
    Login or Signup to reply.
  2. The error itself provides a link to documentation for possible causes of this error: https://learn.microsoft.com/azure/cosmos-db/nosql/troubleshoot-service-unavailable.

    At a high level, in most cases, the error indicates one of two things:

    1. Cosmos DB is not reachable from your client machine.
    2. The auth token is not valid for the endpoint you have given.

    Please double check that you have network access from your client machine to the Cosmos DB endpoint, and that the endpoint/key are correct.

    If you believe you have network connectivity, you may also want to check connectivity modes: https://learn.microsoft.com/azure/cosmos-db/nosql/sdk-connection-modes.

    The default mode for the Java SDK is direct mode, but as you will see, this requires multiple ports to be open, as the SDK will make connections to individual replicas, rather than a singe gateway endpoint. The port ranges that need to be opened are here: https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/sdk-connection-modes#service-port-ranges.

    If you have a restricted network in your local development environment meaning that opening ports is not feasible, try gateway mode:

    client = new CosmosClientBuilder()
             .endpoint("This is where my CosmosDB endpoint is")
             .key("This is where my CosmosDB Primary Key is")
             .consistencyLevel(ConsistencyLevel.EVENTUAL)
             .contentResponseOnWriteEnabled(true)
             .gatewayMode()
             .buildClient();
    

    If this works, that is fine for your dev environment, but we’d still recommend using direct mode in production – this will be better for overall performance, so you may need to investigate what is required to open this up from a networking perspective.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search