本文主要研究一下PowerJob的HttpProcessor

BasicProcessor

tech/powerjob/worker/core/processor/sdk/BasicProcessor.java

public interface BasicProcessor {

    /**
     * 核心处理逻辑
     * 可通过 {@link TaskContext#getWorkflowContext()} 方法获取工作流上下文
     *
     * @param context 任务上下文,可通过 jobParams 和 instanceParams 分别获取控制台参数和OpenAPI传递的任务实例参数
     * @return 处理结果,msg有长度限制,超长会被裁剪,不允许返回 null
     * @throws  Exception 异常,允许抛出异常,但不推荐,最好由业务开发者自己处理
     */
    ProcessResult process(TaskContext context) throws Exception;
}
BasicProcessor是适用于单机运行的基础处理器,它定于了process方法

CommonBasicProcessor

tech/powerjob/official/processors/CommonBasicProcessor.java

@Slf4j
public abstract class CommonBasicProcessor implements BasicProcessor {

    @Override
    public ProcessResult process(TaskContext ctx) throws Exception {

        OmsLogger omsLogger = ctx.getOmsLogger();
        String securityDKey = getSecurityDKey();
        if (SecurityUtils.disable(securityDKey)) {
            String msg = String.format("%s is not enabled, please set '-D%s=true' to enable it", this.getClass().getSimpleName(), securityDKey);
            omsLogger.warn(msg);
            return new ProcessResult(false, msg);
        }

        String status = "unknown";
        Stopwatch sw = Stopwatch.createStarted();

        omsLogger.info("using params: {}", CommonUtils.parseParams(ctx));

        try {
            ProcessResult result = process0(ctx);
            omsLogger.info("execute succeed, using {}, result: {}", sw, result);
            status = result.isSuccess() ? "succeed" : "failed";
            return result;
        } catch (Throwable t) {
            status = "exception";
            omsLogger.error("execute failed!", t);
            return new ProcessResult(false, ExceptionUtils.getMessage(t));
        } finally {
            log.info("{}|{}|{}|{}|{}", getClass().getSimpleName(), ctx.getJobId(), ctx.getInstanceId(), status, sw);
        }
    }

    protected abstract ProcessResult process0(TaskContext taskContext) throws Exception;

    protected String getSecurityDKey() {
        return null;
    }
}
CommonBasicProcessor是一个抽象类,它声明实现BasicProcessor接口,它定义了process0抽象方法,同时还提供了getSecurityDKey方法,其process方法先通过SecurityUtils.disable(securityDKey)先判断是否开启,没有开启直接返回;接着使用try catch来执行process0,最后finally的时候打印一下结果

HttpProcessor

public class HttpProcessor extends CommonBasicProcessor {

    /**
     * Default timeout is 60 seconds.
     */
    private static final int DEFAULT_TIMEOUT = 60;
    private static final int HTTP_SUCCESS_CODE = 200;
    private static final Map<Integer, OkHttpClient> CLIENT_STORE = new ConcurrentHashMap<>();

    @Override
    public ProcessResult process0(TaskContext taskContext) throws Exception {
        OmsLogger omsLogger = taskContext.getOmsLogger();
        HttpParams httpParams = JSON.parseObject(CommonUtils.parseParams(taskContext), HttpParams.class);

        if (httpParams == null) {
            String message = "httpParams is null, please check jobParam configuration.";
            omsLogger.warn(message);
            return new ProcessResult(false, message);
        }

        if (StringUtils.isEmpty(httpParams.url)) {
            return new ProcessResult(false, "url can't be empty!");
        }

        if (!httpParams.url.startsWith("http")) {
            httpParams.url = "http://" + httpParams.url;
        }
        omsLogger.info("request url: {}", httpParams.url);

        // set default method
        if (StringUtils.isEmpty(httpParams.method)) {
            httpParams.method = "GET";
            omsLogger.info("using default request method: GET");
        } else {
            httpParams.method = httpParams.method.toUpperCase();
            omsLogger.info("request method: {}", httpParams.method);
        }

        // set default mediaType
        if (!"GET".equals(httpParams.method)) {
            // set default request body
            if (StringUtils.isEmpty(httpParams.body)) {
                httpParams.body = new JSONObject().toJSONString();
                omsLogger.warn("try to use default request body:{}", httpParams.body);
            }
            if (JSONValidator.from(httpParams.body).validate() && StringUtils.isEmpty(httpParams.mediaType)) {
                httpParams.mediaType = "application/json";
                omsLogger.warn("try to use 'application/json' as media type");
            }
        }

        // set default timeout
        if (httpParams.timeout == null) {
            httpParams.timeout = DEFAULT_TIMEOUT;
        }
        omsLogger.info("request timeout: {} seconds", httpParams.timeout);
        OkHttpClient client = getClient(httpParams.timeout);

        Request.Builder builder = new Request.Builder().url(httpParams.url);
        if (httpParams.headers != null) {
            httpParams.headers.forEach((k, v) -> {
                builder.addHeader(k, v);
                omsLogger.info("add header {}:{}", k, v);
            });
        }

        switch (httpParams.method) {
            case "PUT":
            case "DELETE":
            case "POST":
                MediaType mediaType = MediaType.parse(httpParams.mediaType);
                omsLogger.info("mediaType: {}", mediaType);
                RequestBody requestBody = RequestBody.create(mediaType, httpParams.body);
                builder.method(httpParams.method, requestBody);
                break;
            default:
                builder.get();
        }

        Response response = client.newCall(builder.build()).execute();
        omsLogger.info("response: {}", response);

        String msgBody = "";
        if (response.body() != null) {
            msgBody = response.body().string();
        }

        int responseCode = response.code();
        String res = String.format("code:%d, body:%s", responseCode, msgBody);
        boolean success = true;
        if (responseCode != HTTP_SUCCESS_CODE) {
            success = false;
            omsLogger.warn("{} url: {} failed, response code is {}, response body is {}",
                    httpParams.method, httpParams.url, responseCode, msgBody);
        }
        return new ProcessResult(success, res);
    }

    //......
}    
HttpProcessor继承了CommonBasicProcessor,其process0方法使用CommonUtils.parseParams(taskContext)获取参数,解析为HttpParams类型,然后构建Request.Builder,针对PUT、DELETE、POST构建RequestBody,然后通过client.newCall(builder.build()).execute()执行请求获取返回结果,根据http status来判断是否success

CommonUtils.parseParams

tech/powerjob/official/processors/util/CommonUtils.java

public class CommonUtils {

    private CommonUtils() {

    }

    public static String parseParams(TaskContext context) {
        // 工作流中的总是优先使用 jobParams
        if (context.getWorkflowContext().getWfInstanceId() != null) {
            return context.getJobParams();
        }
        if (StringUtils.isNotEmpty(context.getInstanceParams())) {
            return context.getInstanceParams();
        }
        return context.getJobParams();
    }
}
CommonUtils的parseParams方法针对使用工作流返回jobParams,否则优先返回instanceParams

HttpParams

    @Data
    public static class HttpParams {
        /**
         * POST / GET / PUT / DELETE
         */
        private String method;
        /**
         * the request url
         */
        private String url;
        /**
         * application/json
         * application/xml
         * image/png
         * image/jpeg
         * image/gif
         */
        private String mediaType;

        private String body;

        private Map<String, String> headers;

        /**
         * timeout for complete calls
         */
        private Integer timeout;
    }
HttpParams定义了method、url、mediaType、body、headers、timeout属性

getClient

    private static final Map<Integer, OkHttpClient> CLIENT_STORE = new ConcurrentHashMap<>();

    private static OkHttpClient getClient(Integer timeout) {
        return CLIENT_STORE.computeIfAbsent(timeout, ignore -> new OkHttpClient.Builder()
                .connectTimeout(Duration.ZERO)
                .readTimeout(Duration.ZERO)
                .writeTimeout(Duration.ZERO)
                .callTimeout(timeout, TimeUnit.SECONDS)
                .build());
    }
getClient将相同timeout的OkHttpClient进行了缓存

小结

PowerJob的HttpProcessor继承了CommonBasicProcessor,它接收HttpParams参数,然后使用okhttp进行请求;CommonBasicProcessor是一个抽象类,它声明实现BasicProcessor接口,它定义了process0抽象方法,同时还提供了getSecurityDKey方法,其process方法先通过SecurityUtils.disable(securityDKey)先判断是否开启,没有开启直接返回;接着使用try catch来执行process0,最后finally的时候打印一下结果。


codecraft
11.9k 声望2k 粉丝

当一个代码的工匠回首往事时,不因虚度年华而悔恨,也不因碌碌无为而羞愧,这样,当他老的时候,可以很自豪告诉世人,我曾经将代码注入生命去打造互联网的浪潮之巅,那是个很疯狂的时代,我在一波波的浪潮上留下...


引用和评论

0 条评论