Skip to content

Commit

Permalink
Add Java CDK example
Browse files Browse the repository at this point in the history
  • Loading branch information
jackkleeman committed Jan 7, 2025
1 parent 6821fb8 commit d40c48b
Show file tree
Hide file tree
Showing 21 changed files with 818 additions and 0 deletions.
1 change: 1 addition & 0 deletions .tools/prepare_release_zip.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ create_release_zip templates/rust rust-hello-world
create_release_zip templates/rust-shuttle rust-shuttle-hello-world
create_release_zip templates/typescript-lambda-cdk typescript-hello-world-lambda-cdk
create_release_zip templates/kotlin-gradle-lambda-cdk kotlin-hello-world-lambda-cdk
create_release_zip templates/java-gradle-lambda-cdk java-hello-world-lambda-cdk
create_release_zip templates/python python-hello-world

create_release_zip tutorials/tour-of-restate-go go-tour-of-restate
Expand Down
3 changes: 3 additions & 0 deletions templates/java-gradle-lambda-cdk/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
dist
cdk.out
15 changes: 15 additions & 0 deletions templates/java-gradle-lambda-cdk/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"env": {
"browser": true,
"commonjs": true,
"es2021": true
},
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
"overrides": [],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest"
},
"plugins": ["@typescript-eslint"],
"rules": {}
}
10 changes: 10 additions & 0 deletions templates/java-gradle-lambda-cdk/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
!jest.config.js
node_modules
.cdk.staging
cdk.out
.gradle
lambda/build
*.js
*.d.ts
*.class
cdk.context.json
7 changes: 7 additions & 0 deletions templates/java-gradle-lambda-cdk/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"trailingComma": "all",
"tabWidth": 2,
"semi": true,
"arrowParens": "always",
"printWidth": 120
}
70 changes: 70 additions & 0 deletions templates/java-gradle-lambda-cdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Hello world - Java Lambda (CDK) example

Sample project deploying a Java-based Restate service to AWS Lambda using the AWS Cloud Development Kit (CDK).
The stack uses the Restate CDK constructs library to register the service with against a Restate Cloud environment.

For more information on CDK, please see [Getting started with the AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html).

* [CDK app entry point `lambda-jvm-cdk.ts`](bin/lambda-jvm-cdk.ts)
* [CDK stack consisting of a Lambda function and providing Restate service registration](cdk/lambda-jvm-cdk-stack.ts)
* [Java Lambda handler](lambda) - based on [`hello-world-java`](../java-gradle)

## Download the example

- Via the CLI:
```shell
restate example java-hello-world-lambda-cdk && cd java-hello-world-lambda-cdk
```

- Via git clone:
```shell
git clone [email protected]:restatedev/examples.git
cd examples/templates/java-gradle-lambda-cdk
```

- Via `wget`:
```shell
wget https://github.com/restatedev/examples/releases/latest/download/java-hello-world-lambda-cdk.zip && unzip java-hello-world-lambda-cdk.zip -d java-hello-world-lambda-cdk && rm java-hello-world-lambda-cdk.zip
```

## Deploy

**Pre-requisites:**

* npm
* gradle
* JDK >= 21
* AWS account, bootstrapped for CDK use
* valid AWS credentials with sufficient privileges to create the necessary resources
* an existing [Restate Cloud](https://restate.dev) environment (environment id + API key)

Install npm dependencies:

```shell
npm install
```

To deploy the stack, export the Restate Cloud environment id and API key, and run `cdk deploy`:

```shell
export RESTATE_ENV_ID=env_... RESTATE_API_KEY=key_...
npx cdk deploy
```

The stack output will print out the Restate server ingress URL.

### Test

You can send a test request to the Restate ingress endpoint to call the newly deployed service:

```shell
curl -k ${restateIngressUrl}/Greeter/greet \
-H "Authorization: Bearer $RESTATE_API_KEY" \
-H 'content-type: application/json' -d '"Restate"'
```

### Useful commands

* `npm run build` compile the Lambda handler and synthesize CDK deployment artifacts
* `npm run deploy` perform a CDK deployment
* `npm run destroy` delete the stack and all its resources
24 changes: 24 additions & 0 deletions templates/java-gradle-lambda-cdk/bin/lambda-jvm-cdk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env node

/*
* Copyright (c) 2024 - Restate Software, Inc., Restate GmbH
*
* This file is part of the Restate examples,
* which is released under the MIT license.
*
* You can find a copy of the license in the file LICENSE
* in the root directory of this repository or package or at
* https://github.com/restatedev/examples/
*/

import "source-map-support/register";
import * as cdk from "aws-cdk-lib";
import { LambdaJvmCdkStack } from "../cdk/lambda-jvm-cdk-stack";

const app = new cdk.App();
new LambdaJvmCdkStack(app, "LambdaJvmCdkStack", {
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION,
},
});
59 changes: 59 additions & 0 deletions templates/java-gradle-lambda-cdk/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"app": "npx ts-node --prefer-ts-exts bin/lambda-jvm-cdk.ts",
"watch": {
"include": ["**"],
"exclude": [
"README.md",
"cdk*.json",
"**/*.d.ts",
"**/*.js",
"tsconfig.json",
"package*.json",
"yarn.lock",
"node_modules",
"test"
]
},
"context": {
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/core:checkSecretUsage": true,
"@aws-cdk/core:target-partitions": ["aws", "aws-cn"],
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
"@aws-cdk/aws-iam:minimizePolicies": true,
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
"@aws-cdk/core:enablePartitionLiterals": true,
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
"@aws-cdk/aws-iam:standardizedServicePrincipals": true,
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
"@aws-cdk/aws-route53-patters:useCertificate": true,
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
"@aws-cdk/aws-redshift:columnId": true,
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
"@aws-cdk/aws-kms:aliasNameRef": true,
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true
}
}
62 changes: 62 additions & 0 deletions templates/java-gradle-lambda-cdk/cdk/lambda-jvm-cdk-stack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2024 - Restate Software, Inc., Restate GmbH
*
* This file is part of the Restate examples,
* which is released under the MIT license.
*
* You can find a copy of the license in the file LICENSE
* in the root directory of this repository or package or at
* https://github.com/restatedev/examples/
*/

import * as restate from "@restatedev/restate-cdk";
import * as cdk from "aws-cdk-lib";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as secrets from "aws-cdk-lib/aws-secretsmanager";
import { Construct } from "constructs";

export class LambdaJvmCdkStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: cdk.StackProps) {
super(scope, id, props);

const handler: lambda.Function = new lambda.Function(this, "GreeterService", {
runtime: lambda.Runtime.JAVA_21,
architecture: lambda.Architecture.ARM_64,
code: lambda.Code.fromAsset("lambda/build/distributions/lambda.zip"),
handler: "my.example.LambdaHandler",
timeout: cdk.Duration.seconds(10),
loggingFormat: lambda.LoggingFormat.JSON,
applicationLogLevelV2: lambda.ApplicationLogLevel.DEBUG,
systemLogLevelV2: lambda.SystemLogLevel.INFO,
});

// Set the RESTATE_ENV_ID and RESTATE_API_KEY environment variables to point to your Restate Cloud environment.
// This construct automatically creates an invoker role that Restate Cloud will be able to assume to invoke handlers
// on behalf of your environment. See https://docs.restate.dev/deploy/cloud for more information.
const restateEnvironment = new restate.RestateCloudEnvironment(this, "RestateCloud", {
environmentId: process.env.RESTATE_ENV_ID! as restate.EnvironmentId,
// Warning: this will result in the API key being baked into the CloudFormation template!
// For improved security, pre-populate the secret and pass it to the construct as a reference.
// See: https://docs.aws.amazon.com/secretsmanager/latest/userguide/cdk.html
apiKey: new secrets.Secret(this, "RestateCloudApiKey", {
secretStringValue: cdk.SecretValue.unsafePlainText(process.env.RESTATE_API_KEY!),
}),
});
const deployer = new restate.ServiceDeployer(this, "ServiceDeployer");

// Alternatively, you can deploy a standalone Restate server using the SingleNodeRestateDeployment construct.
// Please see https://docs.restate.dev/deploy/lambda/self-hosted and the construct documentation for more details.
// const vpc = ec2.Vpc.fromLookup(this, "Vpc", { vpcId: "..." });
// const restateEnvironment = new restate.SingleNodeRestateDeployment(this, "Restate", {
// vpc,
// networkConfiguration: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
// });
// const deployer = new restate.ServiceDeployer(this, "ServiceDeployer", {
// vpc,
// securityGroups: [restateEnvironment.adminSecurityGroup],
// });

deployer.deployService("Greeter", handler.currentVersion, restateEnvironment);
new cdk.CfnOutput(this, "restateIngressUrl", { value: restateEnvironment.ingressUrl });
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
arguments=--init-script /var/folders/4x/r9ldvl2j0pldhp2nb9qvxy0w0000gn/T/db3b08fc4a9ef609cb16b96b200fa13e563f396e9bb1ed0905fdab7bc3bc513b.gradle
auto.sync=false
build.scans.enabled=false
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
connection.project.dir=
eclipse.preferences.version=1
gradle.user.home=
java.home=/Library/Java/JavaVirtualMachines/zulu-19.jdk/Contents/Home
jvm.arguments=
offline.mode=false
override.workspace.settings=true
show.console.view=true
show.executions.view=true
53 changes: 53 additions & 0 deletions templates/java-gradle-lambda-cdk/lambda/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import java.net.URI

plugins {
java
}

repositories {
mavenCentral()
}

val restateVersion = "1.2.0"

dependencies {
// Annotation processor
annotationProcessor("dev.restate:sdk-api-gen:$restateVersion")

// Restate SDK
implementation("dev.restate:sdk-api:$restateVersion")
implementation("dev.restate:sdk-http-vertx:$restateVersion")
implementation("dev.restate:sdk-lambda:$restateVersion")
// To use Jackson to read/write state entries (optional)
implementation("dev.restate:sdk-serde-jackson:$restateVersion")

testImplementation(platform("org.junit:junit-bom:5.11.3"))
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("dev.restate:sdk-testing:$restateVersion")

// AWS Lambda-specific logging, see https://docs.aws.amazon.com/lambda/latest/dg/java-logging.html#java-logging-log4j2
val log4j2version = "2.24.2"
implementation("org.apache.logging.log4j:log4j-core:$log4j2version")
implementation("org.apache.logging.log4j:log4j-layout-template-json:$log4j2version")
implementation("com.amazonaws:aws-lambda-java-log4j2:1.6.0")
}

// Setup Java compiler target
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}

tasks.register<Zip>("lambdaZip") {
from(tasks.compileJava.get())
from(tasks.processResources.get())

into("lib") {
from(configurations.runtimeClasspath)
}
}

tasks.build {
dependsOn("lambdaZip")
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading

0 comments on commit d40c48b

Please sign in to comment.