Skip to content

Commit

Permalink
Watcher: Reduce script cache churn by checking for mustache tags (#33978
Browse files Browse the repository at this point in the history
)

Watcher is using a lot of so called TextTemplate fields in a watch
definition, which can use mustache to insert the watch id for example.
For the user it is non-obvious which field is just a string field or
which field is a text template.

This also means, that for every such field, we currently do a script
compilation, even if the field does not contain any mustache syntax.

This will lead to an increased script cache churn, because those
compiled scripts (that only contain a string), will evict other scripts.
On top of that, this also means that an unneeded compilation has
happened, instead of returning that string immediately.

The usages of mustache templating are in all of the actions (most of the time far
more than one compilation) as well as most of the inputs.

Especially when running a lot of watches in parallel, this will reduce
execution times and help reuse of real scripts.
  • Loading branch information
spinscale committed Sep 27, 2018
1 parent bda7bc1 commit a15b1b9
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ public String render(TextTemplate textTemplate, Map<String, Object> model) {
String mediaType = compileParams(detectContentType(template));
template = trimContentType(textTemplate);

int indexStartMustacheExpression = template.indexOf("{{");
if (indexStartMustacheExpression == -1) {
return template;
}

Map<String, Object> mergedModel = new HashMap<>();
if (textTemplate.getParams() != null) {
mergedModel.putAll(textTemplate.getParams());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import static java.util.Collections.singletonMap;
Expand All @@ -31,7 +32,10 @@
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;

public class TextTemplateTests extends ESTestCase {
Expand All @@ -47,7 +51,7 @@ public void init() throws Exception {
}

public void testRender() throws Exception {
String templateText = "_template";
String templateText = "{{_template}}";
Map<String, Object> params = singletonMap("param_key", "param_val");
Map<String, Object> model = singletonMap("model_key", "model_val");
Map<String, Object> merged = new HashMap<>(params);
Expand All @@ -72,7 +76,7 @@ public String execute() {
}

public void testRenderOverridingModel() throws Exception {
String templateText = "_template";
String templateText = "{{_template}}";
Map<String, Object> params = singletonMap("key", "param_val");
Map<String, Object> model = singletonMap("key", "model_val");
ScriptType type = randomFrom(ScriptType.values());
Expand All @@ -94,7 +98,7 @@ public String execute() {
}

public void testRenderDefaults() throws Exception {
String templateText = "_template";
String templateText = "{{_template}}";
Map<String, Object> model = singletonMap("key", "model_val");

TemplateScript.Factory compiledTemplate = templateParams ->
Expand All @@ -113,6 +117,39 @@ public String execute() {
assertThat(engine.render(template, model), is("rendered_text"));
}

public void testDontInvokeScriptServiceOnNonMustacheText() {
assertNoCompilation("this is my text");
assertScriptServiceInvoked("}}{{");
assertScriptServiceInvoked("}}{{ctx.payload}}");
}

private void assertNoCompilation(String input) {
String output = engine.render(new TextTemplate(input), Collections.emptyMap());
assertThat(input, is(output));
verifyZeroInteractions(service);
}

private void assertScriptServiceInvoked(final String input) {
ScriptService scriptService = mock(ScriptService.class);
TextTemplateEngine e = new TextTemplateEngine(Settings.EMPTY, scriptService);

TemplateScript.Factory compiledTemplate = templateParams ->
new TemplateScript(templateParams) {
@Override
public String execute() {
return input.toUpperCase(Locale.ROOT);
}
};

when(scriptService.compile(new Script(ScriptType.INLINE, lang, input,
Collections.singletonMap("content_type", "text/plain"), Collections.emptyMap()), Watcher.SCRIPT_TEMPLATE_CONTEXT))
.thenReturn(compiledTemplate);

String output = e.render(new TextTemplate(input), Collections.emptyMap());
verify(scriptService).compile(any(), any());
assertThat(output, is(input.toUpperCase(Locale.ROOT)));
}

public void testParser() throws Exception {
ScriptType type = randomScriptType();
TextTemplate template =
Expand Down

0 comments on commit a15b1b9

Please sign in to comment.