Problem

Provide a function to determine a server field value, then simply request the value with an age limit. If there is no stored value or the stored value is older than the age limit, it is automatically recalculated, stored for the next call and returned.

Solution

Applies to MarkLogic versions 7+

Create and deploy a library module with the following code.

xquery version "1.0-ml";

module namespace sf = "https://marklogic.com/lazy-load-server-field";

declare variable $trace := "lazy-load-server-field";

declare option xdmp:mapping "false";

(: Get a server field value. Recalculate if older than $age-limit. :)
declare function sf:get-value(
  $name as xs:string, (: the name of the server field :)
  $age-limit as xs:dayTimeDuration?, (: the age limit of the value (empty sequence to ignore age limit) :)
  $f as xdmp:function (: a 0-arity function to get the server field value if necessary :)
) as item()* (: the value in the server field :)
{
  xdmp:trace($trace, "Getting server field " || $name),
  if (fn:function-arity($f) gt 0) then 
    fn:error(xs:QName("FUNCTIONNOTZEROARITY"), "Server field value function must be 0-arity")
  else
    let $sf-timestamp-and-value := xdmp:get-server-field($name)
    let $timestamp := $sf-timestamp-and-value[1]
    let $expired := 
      fn:empty($timestamp) or (fn:exists($age-limit) and fn:current-dateTime() - $timestamp gt $age-limit)
    return 
      if (fn:not($expired)) then 
        (: server field is not expired, return value :)
        fn:subsequence($sf-timestamp-and-value, 2)
      else ( 
        (: server field is expired, use function to get value and set server field :)
        xdmp:trace($trace, "Server field " || $name || " expired, calculating new value"),
        sf:set-value($name, xdmp:apply($f))
      )
};

(: set a server field and add timestamp :)
declare function sf:set-value(
  $name as xs:string, (: the name of the server field :)
  $value as item()* (: the value to set :)
) as item()* (: the value in the server field :)
{
  xdmp:trace($trace, "Setting server field: " || $name),
  let $_ := xdmp:set-server-field(
    $name,
    (fn:current-dateTime(), $value)
  )
  return $value
};

The functionality now lives in a library module. To make use of it, import the module and create a 0-arity function that will calculate the value when needed. If you’re calculating function is not 0-arity, you’ll need to create one that is (eg. by creating an anonymous function that calls your function with the required parameters). Here’s an example assuming that the library module is in /app/lib/lazy-load-server-field.xqy.

xquery version "1.0-ml";

import module namespace sf = "https://marklogic.com/lazy-load-server-field" at "/app/lib/lazy-load-server-field.xqy";

(: this is your existing function to calculate a value you want to store in the server field :)
declare function local:calculate-refdata(
  $s1 as xs:string,
  $s2 as xs:string
) as xs:string
{
  fn:string-join(($s1, $s2), " ")
};

(: add this function to pass a 0-arity version of your function to the library :)
declare function local:get-refdata(
  $s1 as xs:string,
  $s2 as xs:string
) as xs:string
{
  sf:get-value(
    "refdata",
    xs:dayTimeDuration("PT24H"),
    function(){local:calculate-refdata($s1, $s2)}
  )
};

local:get-refdata("Hello", "world")

Discussion

Server fields are specific to an app server and host. This means that in a clustered environment, you may have different values stored in server fields with the same name (on different nodes). However, you will never get back a value that is older than the age limit passed in.

Also note that server fields are not persistent, and are not retained in the event of a server restart. In that case, your server field value will be recalculated by calling the 0-arity function you provided.

Learn More

xdmp:set-server-field

Read how to set the value of a named server field with xdmp:set-server-field, along with its required privileges, and an example.

xdmp:get-server-field

Read how to return the value of a named server field with xdmp:get-server-field, along with its required privileges, and an example.

Application Developer's Guide

Read the documentation that reviews over application development in MarkLogic Server.

This website uses cookies.

By continuing to use this website you are giving consent to cookies being used in accordance with the MarkLogic Privacy Statement.