Skip to content

Conversation

@wolfstudy
Copy link
Member

@wolfstudy wolfstudy commented Apr 30, 2019

Signed-off-by: xiaolong.ran ranxiaolong716@gmail.com

Motivation

Master Issue: #3767

support local-run and cluster mode for go function.

in go function, we can use:

./bin/pulsar-admin functions localrun/create  
--go /Users/wolf4j/github.com/apache/pulsar/pulsar-function-go/examples/outputFunc.go 
--inputs persistent://public/default/my-topic 
--output persistent://public/default/test 
--tenant public 
--namespace default 
--name pulsarfunction 
--classname hellopulsar 
--log-topic logtopic

Different from --jar or --py, --go uploads a complete executable file(including: instance file + user code file)

Signed-off-by: xiaolong.ran <ranxiaolong716@gmail.com>
Copy link
Member

@sijie sijie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wolfstudy great move for supporting go function!

overall looks pretty good. left a few suggestions. PTAL.

It would be good to have an integration test for go function since now it supports running in cluster mode.

@Parameter(
names = "--go",
description = "Path to the main Go file for the function (if the function is written in Go)")
protected String goFile;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I think we are beginning having more and more branches in the pulsar runtime. I guess it might be the time to do a refactor to make the language runtime pluggable in Pulsar Function. So that we don't need to touch the runtime each time we introduce a new language. You don't need to do it right now. but It might be worth creating a task to track that.

protected String pyFile;
@Parameter(
names = "--go",
description = "Path to the main Go file for the function (if the function is written in Go)")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it is the go file. It should be the built go program.

if (isNotBlank(functionConfig.getJar()) && isNotBlank(functionConfig.getPy())) {
throw new ParameterException("Either a Java jar or a Python file needs to"
if (isNotBlank(functionConfig.getJar()) && isNotBlank(functionConfig.getPy()) && isNotBlank(functionConfig.getGo())) {
throw new ParameterException("Either a Java jar or a Python file or a Go file needs to"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest using "Go executable binary" rather than "Go file". A "Go file" is a bit confusing, since it typically means the source files suffixed with .go.

Copy link
Member Author

@wolfstudy wolfstudy Apr 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, in here, we uploaded a source files suffixed with .go.

in getGoInstanceCmd()

args.add("go");
args.add("run");
args.add(originalCodeFileName);

We use go run to run this go file, go run can be divided into two steps:

  1. build .go file is an executable binary
  2. run this executable binary

In this way, the user only needs to upload the .go file, and it is not necessary to upload a compiled binary file.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wolfstudy

Actually I forgot adding the comment there. I don't think we should use "go run", because not every machine installed go. so I would prefer uploading the executable binary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome, will fix it

Tenant string `yaml:"tenant"`
NameSpace string `yaml:"nameSpace"`
Name string `yaml:"name"`
ClassName string `yaml:"className"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think Go needs ClassName.

Go has a completely different way to run functions than Java and Python.

In Java or Python, the instance code is isolated from user code since they support dynamically loading the code. So you need two parameters: --jar or --py to specify whether the function code; and --className to tell the function runtime to the entrypoint (aka className) to invoke the function.

However Go is a static-linking language. The instance is compiled with user function. There is only one entrypoint (which is the main func) for invoking the user function. Hence we only need the code file for go but we don't need a className. So I would suggest not adding a field if it is not used.

* specific language governing permissions and limitations
* under the License.
*/
package org.apache.pulsar.functions.instance.functionforgo;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about just calling this package "org.apache.pulsar.functions.instance.go"? That means it is the package related to go instance.

Copy link
Member Author

@wolfstudy wolfstudy Apr 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent, go is a better choice than functionforgo, will fix it.

return ClearTextSecretsProvider.class.getName();
case PYTHON:
return "secretsprovider.ClearTextSecretsProvider";
case GO:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

throw new UnsupportedOperationException if a feature is not implemented.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

throw new UnsupportedOperationException();

case PYTHON:
return "secretsprovider.EnvironmentBasedSecretsProvider";
case GO:
return "";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

throw new UnsupportedOperationException if a feature is not implemented.

}

if (functionConfig.getWindowConfig() != null) {
throw new IllegalArgumentException("There is currently no support windowing in golang");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
throw new IllegalArgumentException("There is currently no support windowing in golang");
throw new IllegalArgumentException("Windowing is not supported in Go function yet");


private static void doGolangChecks(FunctionConfig functionConfig) {
if (functionConfig.getProcessingGuarantees() == FunctionConfig.ProcessingGuarantees.EFFECTIVELY_ONCE) {
throw new RuntimeException("Effectively-once processing guarantees not yet supported in Golang");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
throw new RuntimeException("Effectively-once processing guarantees not yet supported in Golang");
throw new RuntimeException("Effectively-once processing guarantees not yet supported in Go function");

}

if (functionConfig.getMaxMessageRetries() != null && functionConfig.getMaxMessageRetries() >= 0) {
throw new IllegalArgumentException("Message retries not yet supported in golang");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
throw new IllegalArgumentException("Message retries not yet supported in golang");
throw new IllegalArgumentException("Message retries not yet supported in Go function");

@sijie sijie added this to the 2.4.0 milestone Apr 30, 2019
@sijie sijie added the type/feature The PR added a new feature or issue requested a new feature label Apr 30, 2019
Signed-off-by: xiaolong.ran <ranxiaolong716@gmail.com>
pom.xml Outdated
<version>1.48</version>
</dependency>

<dependency>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment about using Jackson instead

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.*;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use wildcards

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool, good suggestion

classLoader = loadJar(file);
}
} else if (functionConfig.getRuntime() == FunctionConfig.Runtime.GO) {
userCodeFile = functionConfig.getGo();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also check for python runtime here and throw an exception if its not Java, Go, or python

String output = yaml.dumpAs(goInstanceConfig, Tag.MAP, null);
String fileName = String.format("%s_%s_%s", goInstanceConfig.getTenant(), goInstanceConfig.getNameSpace(),
goInstanceConfig.getName());
File ymlFile = File.createTempFile(fileName, ".yml");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file needs to be cleaned somehow.

wolfstudy added 2 commits May 1, 2019 12:23
Signed-off-by: xiaolong.ran <ranxiaolong716@gmail.com>
Signed-off-by: xiaolong.ran <ranxiaolong716@gmail.com>
@wolfstudy
Copy link
Member Author

@jerrypeng PTAL again thanks

wolfstudy added 2 commits May 2, 2019 11:09
Signed-off-by: xiaolong.ran <ranxiaolong716@gmail.com>
Signed-off-by: xiaolong.ran <ranxiaolong716@gmail.com>
@wolfstudy
Copy link
Member Author

@sijie @jerrypeng PTAL again

Signed-off-by: xiaolong.ran <ranxiaolong716@gmail.com>
@wolfstudy
Copy link
Member Author

run java8 tests

goInstanceConfig.setKillAfterIdleMs(0);

// Parse the contents of goInstanceConfig into json form string
ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use ObjectMapperFactory.getThreadLocal() instead of creating a new ObjectMapper

Signed-off-by: xiaolong.ran <ranxiaolong716@gmail.com>
Copy link
Member

@sijie sijie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overall looks great! left one mintor comment - UnsupportedOperationException should be thrown when a method is not implemented.

return ClearTextSecretsProvider.class.getName();
case PYTHON:
return "secretsprovider.ClearTextSecretsProvider";
case GO:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

throw new UnsupportedOperationException();

@sijie
Copy link
Member

sijie commented May 3, 2019

run java8 tests

if (StringUtils.isNotEmpty(extraDependenciesDir)) {
args.add("PYTHONPATH=${PYTHONPATH}:" + extraDependenciesDir);
}
} else if (instanceConfig.getFunctionDetails().getRuntime() == Function.FunctionDetails.Runtime.GO) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this check is necessary

@jerrypeng
Copy link
Contributor

LGTM @srkukarni you want to take a look as well?

Signed-off-by: xiaolong.ran <ranxiaolong716@gmail.com>
@wolfstudy
Copy link
Member Author

run java8 tests

1 similar comment
@wolfstudy
Copy link
Member Author

run java8 tests

@wolfstudy
Copy link
Member Author

ping @srkukarni
do you want to take a look as well?

Signed-off-by: xiaolong.ran <ranxiaolong716@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/function type/feature The PR added a new feature or issue requested a new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants