1. やること
- Salesforce Functionsを触ってみる
2. バージョンや背景など
- Summer '21 (2021/9/30時点)
- FunctionsのBeta登録に遅れたため、組織に接続できない
- FunctionsはWinter '22でGAだけど、リリース直前でまだGAになっていない
3. 試したこと
3.1. Beta登録を試みた
- https://sfdc.co/functions-beta
- Beta登録のためのアンケートがなくなってしまった様子
3.2. Salesforce Functions SFDX Pluginのインストールを試みた
-
https://developer.salesforce.com/docs/platform/functions/guide/install_intro.html
- Install the Salesforce Functions SFDX Plugin
- 以下のコマンドを実施
% sfdx update
% sfdx plugins:install @salesforce/plugin-functions
- 実施結果
% sfdx --version
sfdx-cli/7.119.2 darwin-x64 node-v14.17.6
% sfdx plugins
functions 0.2.50
└─ @oclif/plugin-not-found 1.2.4
3.3. Salesforce組織でFunctionsの有効化を試みた
- https://developer.salesforce.com/docs/platform/functions/guide/devhub-auth.html
- [設定 > 機能設定 > 関数]のページを表示したが、やはりまだ有効化できない様子
- クイック検索で「関数」だけでなく「function」でも、該当ページがヒットした
- [User]では「ユーザ」ページはヒットしなかった
- 英語でもヒットするようになると少し嬉しいかもしれない
3.4. Functionの作成を試みた
- https://developer.salesforce.com/docs/platform/functions/guide/create-dx-project.html
- SFDXプロジェクトを作成する
- FunctionはSFDXプロジェクト内に作成するため
sfdx generate:project -n MyFunctionProject
% sfdx generate:project -n MyFunctionProject
create MyFunctionProject/config/project-scratch-def.json
create MyFunctionProject/README.md
create MyFunctionProject/sfdx-project.json
create MyFunctionProject/.husky/pre-commit
create MyFunctionProject/.vscode/extensions.json
create MyFunctionProject/.vscode/launch.json
create MyFunctionProject/.vscode/settings.json
create MyFunctionProject/force-app/main/default/lwc/.eslintrc.json
create MyFunctionProject/force-app/main/default/aura/.eslintrc.json
create MyFunctionProject/scripts/soql/account.soql
create MyFunctionProject/scripts/apex/hello.apex
create MyFunctionProject/.eslintignore
create MyFunctionProject/.forceignore
create MyFunctionProject/.gitignore
create MyFunctionProject/.prettierignore
create MyFunctionProject/.prettierrc
create MyFunctionProject/jest.config.js
create MyFunctionProject/package.json
- Functionを作成する
- 公式サイトの例ではjavascriptだが、javaを選択してみる
- 2021/9/30時点で、公式サイトの例のオプション名が古いよう。--nameを使用すると--function-nameを使ってほしいとのメッセージが出た
sfdx generate:function --function-name myfunction --language java
% cd MyFunctionProject
% sfdx generate:function --function-name myfunction --language java
Created java function myfunction in ~~省略~~/MyFunctionProject/functions/myfunction.
Before creating Scratch Orgs for development, please ensure that:
1. Enable Functions in your DevHub org
2. Add Functions to the "features" list in your scratch org definition JSON file, e.g. "features": ["Functions"]
スクラッチ組織を作成する前に実施すべきことが記載されている。
1. Enable Functions in your DevHub org
は、先ほど試みたが、今(2021/9/30)はまだできない
3.3. Functionsをfeaturesに設定して、スクラッチ組織の作成を試みた
- DevHub組織でFunctionsを有効化できていないので失敗すると思われる
-
config/project-scratch-def.json
内のfeaturesにFunctionsを追加
% cat config/project-scratch-def.json
{
"orgName": "company",
"edition": "Developer",
"features": ["EnableSetPasswordInApi", "Functions"],
"settings": {
"lightningExperienceSettings": {
"enableS1DesktopEnabled": true
},
"mobileSettings": {
"enableS1EncryptedStoragePref2": false
}
}
}
- スクラッチ組織を作成してみる
- Functionsが有効化していないため、スクラッチ組織の作成に失敗する様子
% sfdx force:org:create -f config/project-scratch-def.json -a scratch -v devhub
ERROR running force:org:create: Functions は有効な機能値ではありません。
3.4. 作成されたFunctionsのコードを確認してみた
- SFDXプロジェクトの配下に
functions
というフォルダが作成される
% ls
README.md force-app jest.config.js scripts
config functions package.json sfdx-project.json
-
functions
フォルダ内に作成したmyFunction
がある
% ls functions
myfunction
- 作成されたFunctionはMaven形式の様子
% cd functions/myfunction
% ls
mvnw mvnw.cmd pom.xml project.toml src
- 作成されたpom.xmlは以下のようになっていた
- Javaバージョンは1.8
-
com.salesforce.functions:sf-fx-sdk-java
をdependsしている - JUnit4だったりする
-
mvnw clean package
でBUILD SUCCESSすることを確認
shigeo.tejima@tejimasgeonoair myfunction % cat pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>myfunction</artifactId>
<version>1.0-SNAPSHOT</version>
<name>myfunction</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.salesforce.functions</groupId>
<artifactId>sf-fx-sdk-java</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.6.28</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.spotify</groupId>
<artifactId>hamcrest-pojo</artifactId>
<version>1.2.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
- 作成されたコードは以下のようになっていた
% cd src/main/java/com/example/
% ls
Account.java FunctionInput.java FunctionOutput.java MyfunctionFunction.java
% cat Account.java
package com.example;
public class Account {
private final String id;
private final String name;
public Account(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}
% cat FunctionInput.java
package com.example;
public class FunctionInput {
}
% cat FunctionOutput.java
package com.example;
import java.util.List;
public class FunctionOutput {
private final List<Account> accounts;
public FunctionOutput(List<Account> accounts) {
this.accounts = accounts;
}
public List<Account> getAccounts() {
return accounts;
}
}
% cat MyfunctionFunction.java
package com.example;
import com.salesforce.functions.jvm.sdk.Context;
import com.salesforce.functions.jvm.sdk.InvocationEvent;
import com.salesforce.functions.jvm.sdk.SalesforceFunction;
import com.salesforce.functions.jvm.sdk.data.Record;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* Describe MyfunctionFunction here.
*/
public class MyfunctionFunction implements SalesforceFunction<FunctionInput, FunctionOutput> {
private static final Logger LOGGER = LoggerFactory.getLogger(MyfunctionFunction.class);
@Override
public FunctionOutput apply(InvocationEvent<FunctionInput> event, Context context)
throws Exception {
List<Record> records =
context.getOrg().get().getDataApi().query("SELECT Id, Name FROM Account").getRecords();
LOGGER.info("Function successfully queried {} account records!", records.size());
List<Account> accounts = new ArrayList<>();
for (Record record : records) {
String id = record.getStringField("Id").get();
String name = record.getStringField("Name").get();
accounts.add(new Account(id, name));
}
return new FunctionOutput(accounts);
}
}
-
組織から取引先(Account)のId,Nameを検索した結果を返す処理の様子
- 入力, 出力ともにPOJOで書けるようだ
- Functionは
SalesforceFunction<T,S>
を実装する
-
作成されたテストコードを確認してみる
% cd src/test/java/com/example
% ls
FunctionTest.java
% cat FunctionTest.java
package com.example;
import com.salesforce.functions.jvm.sdk.Context;
import com.salesforce.functions.jvm.sdk.InvocationEvent;
import com.salesforce.functions.jvm.sdk.Org;
import com.salesforce.functions.jvm.sdk.data.Record;
import com.salesforce.functions.jvm.sdk.data.RecordQueryResult;
import org.junit.Test;
import org.mockito.Mockito;
import java.util.Arrays;
import java.util.Optional;
import static com.spotify.hamcrest.pojo.IsPojo.pojo;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItems;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class FunctionTest {
@Test
public void test() throws Exception {
MyfunctionFunction function = new MyfunctionFunction();
FunctionOutput functionOutput = function.apply(createEventMock(), createContextMock());
assertThat(
functionOutput.getAccounts(),
hasItems(
pojo(Account.class)
.withProperty("id", equalTo("5003000000D8cuIQAA"))
.withProperty("name", equalTo("Account One, inc.")),
pojo(Account.class)
.withProperty("id", equalTo("6003000000D8cuIQAA"))
.withProperty("name", equalTo("Account Two, inc."))));
}
private Context createContextMock() {
Context mockContext = mock(Context.class);
when(mockContext.getOrg()).then(i1 -> {
Org mockOrg = mock(Org.class, Mockito.RETURNS_DEEP_STUBS);
when(mockOrg.getDataApi().query("SELECT Id, Name FROM Account")).then(i2 -> {
RecordQueryResult mockResult = mock(RecordQueryResult.class);
Record firstRecord = mock(Record.class);
when(firstRecord.getStringField("Id")).thenReturn(Optional.of("5003000000D8cuIQAA"));
when(firstRecord.getStringField("Name")).thenReturn(Optional.of("Account One, inc."));
Record secondRecord = mock(Record.class);
when(secondRecord.getStringField("Id")).thenReturn(Optional.of("6003000000D8cuIQAA"));
when(secondRecord.getStringField("Name")).thenReturn(Optional.of("Account Two, inc."));
when(mockResult.getRecords()).thenReturn(Arrays.asList(firstRecord, secondRecord));
return mockResult;
});
return Optional.of(mockOrg);
});
return mockContext;
}
private InvocationEvent<FunctionInput> createEventMock() {
return mock(InvocationEvent.class);
}
}
- 組織に接続が必要な箇所や
InvocationEvent
などは、モックしてテストできる
3.5. 作成されたFunctionをローカルで動かしてみた
- https://developer.salesforce.com/docs/platform/functions/guide/test-local-function.html
- Functionsが有効なスクラッチ組織がないため、作成されたコードの内
MyfunctionFunction.java
を以下のように組織に依存しない内容に変更する
/*
List<Record> records =
context.getOrg().get().getDataApi().query("SELECT Id, Name FROM Account").getRecords();
LOGGER.info("Function successfully queried {} account records!", records.size());
List<Account> accounts = new ArrayList<>();
for (Record record : records) {
String id = record.getStringField("Id").get();
String name = record.getStringField("Name").get();
accounts.add(new Account(id, name));
}
*/
// demo code without org
List<Account> accounts = new ArrayList<>();
accounts.add(new Account("id-1", "account 1"));
accounts.add(new Account("id-2", "account 2"));
-
sfdx run:function:start
- 実行時のログは以下のGistに添付
- https://gist.github.com/ShigeoTejima/1bc51717032825ebdd08db6f7130e21b
-
sfdx run:function -l http://localhost:8080 -p '{}'
- FunctionInputにはパラメータがないため、上記のようなリクエストを送信
% sfdx run:function -l http://localhost:8080 -p '{}'
› Warning: No -o connected org or defaultusername found, context will be partially initialized
Using defaultusername undefined login credential to initialize context
POST http://localhost:8080... 200
{
"accounts": [
{
"id": "id-1",
"name": "account 1"
},
{
"id": "id-2",
"name": "account 2"
}
]
}
- 期待通りのレスポンスが返ってきた
- -oオプションで指定するか、defaultusernameを設定するとその組織が使用されそうである
- 以下のようにhelpを表示すると、-oオプションの説明にそのような記載がある
% sfdx help run:function
Send a cloudevent to a function.
USAGE
$ sfdx run:function
OPTIONS
-H, --headers=headers Set headers.
-l, --function-url=function-url Url of the function to run.
-o, --connected-org=connected-org Username or alias for the target org; overrides default target org.
-p, --payload=payload Set the payload of the cloudevent. also accepts @file.txt format.
-s, --structured Set the cloudevent to be emitted as a structured cloudevent (json).
EXAMPLES
$ sfdx run:function -l http://localhost:8080 -p '{"id": 12345}'
$ sfdx run:function -l http://localhost:8080 -p '@file.json'
$ echo '{"id": 12345}' | sfdx run:function -l http://localhost:8080
$ sfdx run:function -l http://localhost:8080 -p '{"id": 12345}' --structured
COMMANDS
run:function:start Build and run function image locally.
3.6. スクラッチ組織を作成して、ローカルで動かしたFunctionから接続できるか試してみた
- スクラッチ組織を作成する
sfdx force:org:create -f config/project-scratch-def.json -a scratch -v devhub
- DevHub組織はFunctionsが有効化されていない
-
config/project-scratch-def.json
のfeaturesにFunctionsは追加していない
- 取引先(Account)をいくつか作成する
- 作成されたFunctionのコード
MyfunctionFunction.java
を元に戻す sfdx run:function:start
sfdx run:function -l http://localhost:8080 -p '{}' -o scratch
- 以下のようにスクラッチ組織の取引先(Account)の情報がレスポンスとして返ってきた
- defaultusernameにスクラッチ組織が設定されている場合は、-oオプションなしでも同様の結果となった
% sfdx run:function -l http://localhost:8080 -p '{}' -o scratch
Using scratch login credential to initialize context
POST http://localhost:8080... 200
{
"accounts": [
{
"id": "0010l00001M37iwAAB",
"name": "取引先Bar"
},
{
"id": "0010l00001M35GQAAZ",
"name": "エンタイトルメントの取引先のサンプル"
},
{
"id": "0010l00001M37imAAB",
"name": "Account Foo"
}
]
}
- defaultusernameが未設定、かつ-oオプションでスクラッチ組織を指定しないで、組織に接続しようとすると以下のようなエラーとなった
% sfdx run:function -l http://localhost:8080 -p '{}'
› Warning: No -o connected org or defaultusername found, context will be partially initialized
Using defaultusername undefined login credential to initialize context
POST http://localhost:8080... 500 Internal Server Error
› Error: Function threw exception: com.salesforce.functions.jvm.sdk.data.error.DataApiException (IOException while executing API
› request!)
› com.salesforce.functions.jvm.sdk.data.error.DataApiException: IOException while executing API request!
› at com.salesforce.functions.jvm.runtime.sdk.DataApiImpl.executeRequest(DataApiImpl.java:188)
› at com.salesforce.functions.jvm.runtime.sdk.DataApiImpl.query(DataApiImpl.java:57)
› at com.example.MyfunctionFunction.apply(MyfunctionFunction.java:25)
› at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
› at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
› at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
› at java.lang.reflect.Method.invoke(Method.java:498)
› at com.salesforce.functions.jvm.runtime.sfjavafunction.SalesforceFunctionsProjectFunctionsScanner.lambda$scan$0(SalesforceFunct
› ionsProjectFunctionsScanner.java:402)
› at com.salesforce.functions.jvm.runtime.sfjavafunction.Slf4j1MdcDataInvocationWrapper.invoke(Slf4j1MdcDataInvocationWrapper.jav
› a:81)
› at com.salesforce.functions.jvm.runtime.sfjavafunction.SalesforceFunction.apply(SalesforceFunction.java:68)
› at com.salesforce.functions.jvm.runtime.sfjavafunction.SalesforceFunction.apply(SalesforceFunction.java:31)
› at com.salesforce.functions.jvm.runtime.invocation.undertow.UndertowInvocationInterface$ProjectFunctionHandler.handleRequest(Un
› dertowInvocationInterface.java:160)
› at io.undertow.server.Connectors.executeRootHandler(Connectors.java:387)
› at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:852)
› at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
› at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2019)
› at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1558)
› at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1449)
› at org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1280)
› at java.lang.Thread.run(Thread.java:748)
› Caused by: org.apache.http.client.ClientProtocolException
› at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:187)
› at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
› at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
› at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
› at com.salesforce.functions.jvm.runtime.sdk.restapi.RestApi.execute(RestApi.java:75)
› at com.salesforce.functions.jvm.runtime.sdk.DataApiImpl.executeRequest(DataApiImpl.java:182)
› ... 19 more
› Caused by: org.apache.http.ProtocolException: Target host is not specified
› at org.apache.http.impl.conn.DefaultRoutePlanner.determineRoute(DefaultRoutePlanner.java:71)
› at org.apache.http.impl.client.InternalHttpClient.determineRoute(InternalHttpClient.java:125)
› at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
› ... 24 more
›
3.6. dockerのイメージとコンテナを確認してみた
- Dockerのイメージ
-
heroku/pack
、heroku/buildpacks
が追加されている -
myfunction
という作成したFunctionと同名のイメージが追加されている -
<none>
はmyfunction
の前回のイメージ
-
% docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
heroku/pack 20 822ae55e45ce 3 hours ago 567MB
<none> <none> 74806d6c3d7b 41 years ago 710MB
myfunction latest c871af01d206 41 years ago 710MB
heroku/buildpacks 20 094f2b3353e5 41 years ago 1.54GB
- Dockerのコンテナ
-
myfunction
イメージでコンテナが起動している
-
% docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fd1e377bacb2 myfunction "/cnb/process/web" 7 minutes ago Up 6 minutes 0.0.0.0:8080->8080/tcp, 0.0.0.0:9229->9229/tcp myfunction
3.7. Java11を試みた
- pom.xmlでバージョン指定している箇所を修正
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<java.version>11</java.version>
</properties>
- ローカルで
mvnw clean package
して問題ないことを確認 -
sfdx run:function:start
してみる- 以下のようにエラーで落ちた
% sfdx run:function:start
Building myfunction
20: Pulling from heroku/buildpacks
Digest: sha256:e007b9a6a71bfdbb80e412cae139d46bc98ffa580e3e780f653e89b3055be9b6
Status: Image is up to date for heroku/buildpacks:20
20: Pulling from heroku/pack
Digest: sha256:694f287e23692b3914d32aaa9c0227fc95359c16bc12ef68f8251ab3a7a6c706
Status: Image is up to date for heroku/pack:20
===> DETECTING
======== Output: heroku/ruby@0.0.1 ========
no
err: heroku/ruby@0.0.1 (1)
heroku/jvm 0.1.8
heroku/maven 0.2.5
heroku/jvm-function-invoker 0.5.3
===> ANALYZING
Restoring metadata for "heroku/jvm:jre" from app image
Restoring metadata for "heroku/jvm:jdk" from cache
Restoring metadata for "heroku/jvm:utils" from cache
Restoring metadata for "heroku/maven:maven-repository" from cache
Restoring metadata for "heroku/jvm-function-invoker:bundle" from app image
Restoring metadata for "heroku/jvm-function-invoker:opt" from app image
Restoring metadata for "heroku/jvm-function-invoker:runtime" from app image
===> RESTORING
Restoring data for "heroku/jvm:jdk" from cache
Restoring data for "heroku/jvm:utils" from cache
Restoring data for "heroku/maven:maven-repository" from cache
Restoring data for "heroku/jvm-function-invoker:runtime" from cache
===> BUILDING
[Installing Java]
JDK 1.8 installed from cache
JRE 1.8 installed from cache
[Installing Maven]
[INFO] Maven wrapper detected, skipping installation.
[Executing Maven]
[INFO] $ ./mvnw -DskipTests clean install
[INFO] Scanning for projects...
[INFO]
[INFO] --
---------------------< com.example:myfunction >-----------------------
[
INFO] Building myfunction 1.0-SNAPSHOT
[INFO] --------------
------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-
clean-plugin:3.1.0:clean (default-clean) @ myfunction ---
[INFO] Deleting /workspace/target
[INFO]
[INFO] --- maven-resources-plugin:3.0.2
:resources (default-resources) @ myfunction ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip
non existing resourceDirectory /workspace/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ myfunction ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 4 source files to /workspace/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.146 s
[INFO] Finished at: 2021-09-30T04:08:34Z
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project myfunction: Fatal error compiling: invalid target release: 11 -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
[ERROR: Failed to build app with Maven]
We're sorry this build is failing! If you can't find the issue in application code,
please submit a ticket so we can help: https://help.heroku.com/
ERROR: failed to build: exit status 1
ExitError: EEXIT: 0
at Object.exit (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@oclif/errors/lib/index.js:19:11)
at EventEmitter.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@salesforce/plugin-functions/lib/commands/run/function/start.js:59:30)
at EventEmitter.emit (events.js:400:28)
at EventEmitter.emit (domain.js:470:12)
at Interface.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@heroku/functions-core/dist/benny.js:106:39)
at Interface.emit (events.js:400:28)
at Interface.emit (domain.js:470:12)
at Interface._onLine (readline.js:364:10)
at Interface._normalWrite (readline.js:509:12)
at Socket.ondata (readline.js:216:10) {
oclif: { exit: 0 },
code: 'EEXIT'
}
ExitError: EEXIT: 0
at Object.exit (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@oclif/errors/lib/index.js:19:11)
at EventEmitter.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@salesforce/plugin-functions/lib/commands/run/function/start.js:59:30)
at EventEmitter.emit (events.js:400:28)
at EventEmitter.emit (domain.js:470:12)
at Interface.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@heroku/functions-core/dist/benny.js:106:39)
at Interface.emit (events.js:400:28)
at Interface.emit (domain.js:470:12)
at Interface._onLine (readline.js:364:10)
at Interface._normalWrite (readline.js:509:12)
at Socket.ondata (readline.js:216:10) {
oclif: { exit: 0 },
code: 'EEXIT'
}
ExitError: EEXIT: 0
at Object.exit (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@oclif/errors/lib/index.js:19:11)
at EventEmitter.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@salesforce/plugin-functions/lib/commands/run/function/start.js:59:30)
at EventEmitter.emit (events.js:400:28)
at EventEmitter.emit (domain.js:470:12)
at Interface.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@heroku/functions-core/dist/benny.js:106:39)
at Interface.emit (events.js:400:28)
at Interface.emit (domain.js:470:12)
at Interface._onLine (readline.js:364:10)
at Interface._normalWrite (readline.js:509:12)
at Socket.ondata (readline.js:216:10) {
oclif: { exit: 0 },
code: 'EEXIT'
}
ExitError: EEXIT: 0
at Object.exit (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@oclif/errors/lib/index.js:19:11)
at EventEmitter.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@salesforce/plugin-functions/lib/commands/run/function/start.js:59:30)
at EventEmitter.emit (events.js:400:28)
at EventEmitter.emit (domain.js:470:12)
at Interface.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@heroku/functions-core/dist/benny.js:106:39)
at Interface.emit (events.js:400:28)
at Interface.emit (domain.js:470:12)
at Interface._onLine (readline.js:364:10)
at Interface._normalWrite (readline.js:509:12)
at Socket.ondata (readline.js:216:10) {
oclif: { exit: 0 },
code: 'EEXIT'
}
ExitError: EEXIT: 0
at Object.exit (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@oclif/errors/lib/index.js:19:11)
at EventEmitter.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@salesforce/plugin-functions/lib/commands/run/function/start.js:59:30)
at EventEmitter.emit (events.js:400:28)
at EventEmitter.emit (domain.js:470:12)
at Interface.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@heroku/functions-core/dist/benny.js:106:39)
at Interface.emit (events.js:400:28)
at Interface.emit (domain.js:470:12)
at Interface._onLine (readline.js:364:10)
at Interface._normalWrite (readline.js:509:12)
at Socket.ondata (readline.js:216:10) {
oclif: { exit: 0 },
code: 'EEXIT'
}
ExitError: EEXIT: 0
at Object.exit (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@oclif/errors/lib/index.js:19:11)
at EventEmitter.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@salesforce/plugin-functions/lib/commands/run/function/start.js:59:30)
at EventEmitter.emit (events.js:400:28)
at EventEmitter.emit (domain.js:470:12)
at Interface.<anonymous> (/Users/shigeo.tejima/.local/share/sfdx/node_modules/@heroku/functions-core/dist/benny.js:106:39)
at Interface.emit (events.js:400:28)
at Interface.emit (domain.js:470:12)
at Interface._onLine (readline.js:364:10)
at Interface._normalWrite (readline.js:509:12)
at Socket.ondata (readline.js:216:10) {
oclif: { exit: 0 },
code: 'EEXIT'
}
Error: Build exited with: executing lifecycle: failed with status code: 145
- heroku-buildpack-javaを眺める
- 以下のような記述が見つかったので、試してみる
Choose a JDK
Create a system.properties file in the root of your project directory and set java.runtime.version=1.8.
- system.propertiesファイルを作成して、java.runtime.versionを指定する
% echo "java.runtime.version=11" > system.properties
% cat system.properties
java.runtime.version=11
% ls
mvnw pom.xml src target
mvnw.cmd project.toml system.properties
-
sfdx run:function:start
してみる- 以下のようにJDK 11がインストールされたログが表示された
- 正常に起動して、functionの呼び出しも成功した
[Installing Java]
JDK 11 installed
JRE 11 installed
3.8. Java17を試みた
-
java.runtime.version=17
も正常に動作した
[Installing Java]
JDK 17 installed
JRE 17 installed
(追記)
3.9. キャッシュのクリア
- イメージを削除した後で再度作成する場合など、キャッシュが残っていて正常に動作しない場合があった
- 事象が発生した例
- Java8でイメージを作成して起動
- Java11でイメージを作成して起動
- イメージを削除
- Java11でイメージを作成しようとしたら、起動しなかった
- 事象が発生した例
- 以下のコマンドでキャッシュをクリアしてイメージを作成して起動する
sfdx run:function:start -v --clear-cache
4. 試せなかったこと
- Functionのデプロイ
- ApexからのFunction実行