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
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.
CreateItem()
ofCosmosContainer
class. You have used the same but have not initialized thecontainer
object.To initialize
container
object ofCosmosContainer
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:
Sample class Product.java
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:
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:
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.