Loading TOC...
REST Application Developer's Guide (PDF)

REST Application Developer's Guide — Chapter 6

Managing Transactions

The REST Client API provides transaction control through the /transactions service and a txid parameter available on document manipulation and search requests. This section covers the following topics:

Service Summary

Many of the services available through the REST Client API allow you to perform an operation in the context of a specific transaction by passing a transaction id in a txid parameter. The /transactions service supports the creation and administration of these transactions.

The /transactions service supports the following operations:

Operation Method Description More Information
Create POST Create a multi-statement transaction. See Creating a Transaction. Creating a Transaction

The /transactions/{txid} service supports the following operations:

Operation Method Description More Information
Commit or Rollblack POST Commit or rollback an open transaction. Committing or Rolling Back a Transaction
Status GET Retrieve transaction status in XML or JSON. Checking Transaction Status

Overview of RESTful Transactions

This section gives a brief introduction to the MarkLogic Server transaction model as it applies to the REST Client API. For a full discussion of the transaction model, see Understanding Transactions in MarkLogic Server in the Application Developer's Guide..

By default, each request to a REST Client API service is equivalent to a single statement transaction. That is, the request is evaluated as single transaction.

For example, when you update a document in the database by making a PUT request to the /documents service, the service effectively creates a new transaction, updates the document, commits the transaction, and then sends back a response. The update is immediately visible in the database and available to other requests.

The REST Client API also allows your application to take direct control of transaction boundaries so that multiple request are evaluated in the same transaction context. This is equivalent to the multi-statement transactions described in Multi-Statement Transaction Concept Summary in the Application Developer's Guide.

Using multi-statement transactions, you can make several update requests and commit them as a single transaction, ensuring either all or none of the updates appear in the database. The document manipulation and search capabilities of the REST Client API support multi-statement transactions.

To use multi-statement transactions:

  1. Create a multi-statement transaction by sending a POST request to the /transactions service. The service returns a transaction id. See Creating a Transaction.
  2. Evaluate one or more requests in the context of the transaction by including the transaction id in the txid request parameter. See Associating a Transaction with a Request.
  3. Commit or rollback the transaction by sending a POST request to the /transactions service. See Committing or Rolling Back a Transaction.

If your application interacts with MarkLogic Server through a load balancer, you might need to include a load balancer session cookie in your requests to preserve session affinity. For details, see Managing Transactions When Using a Load Balancer.

When you explicitly create a transaction, you must explicitly commit or roll it back. Failure to do so leaves the transaction open until the request or transaction timeout expires. Open transactions can hold locks and consume system resources.

If the request or transaction timeout expires before a transaction is committed, the transaction is automatically rolled back and all updates are discarded. Configure the request timeout of the App Server using the Admin UI. Configure the timeout of a single transaction by setting the timeLimit request parameter during transaction creation.

Note that if you're using multi-statement transactions, you must create, use, and commit (or rollback) on the transaction using the same database. You cannot create a transaction on one database and then attempt to perform an operation such as read, write, or search using the transaction id and a different database.

Creating a Transaction

To create a transaction, send a POST request to the /transactions service with a URL of the form:

http://host:port/version/transactions

The service responds with a transaction id in the Location response header. Use the transaction id to control the transaction in which MarkLogic Server evaluates future requests; see Associating a Transaction with a Request.

The transaction id returned in the Location header is of the form. You can use this resource path to subsequently commit or rollback the transaction, as described in Committing or Rolling Back a Transaction.

/version/transactions/txnid

For example:

# Windows users, see Modifying the Example Commands for Windows 
$ curl -X POST -d "" --anyauth --user user:password \
    -H "Content-type: text/plain" \
    http://localhost:8000/LATEST/transactions
...
HTTP/1.1 303 See Created Transaction
Location: /v1/transactions/3148548124558550433

When supplying the transaction id to future requests, use only the txnid portion. For example:

$ curl -X PUT -T ./example.xml --anyauth --user user:password \
  'http://localhost:8000/LATEST/documents?uri=/xml/example.xml&txid=3148548124558550433'

Transactions created using the /transactions service must be explicitly committed or rolled back. Failure to commit or rollback the transaction before the request timeout expires causes an automatic rollback. You can assign a shorter time limit to a transaction using the timeLimit URL parameter:

http://host:port/version/transactions?timeLimit=seconds

As a convenience for identifying a transaction in server status reports, you can assign a name to the transaction. The default transaction name is client-txn. To assign a transaction, add the name URL parameter to your request:

http://host:port/version/transactions?name=txn_name

Associating a Transaction with a Request

Once you create a transaction, as described in Creating a Transaction, you can evaluate document manipulation and search requests in that transaction by supplying the transaction id wherever a txid URL parameter is supported.

For example, to perform a document update in the context of a specific transaction, include the transaction id in a PUT request to the /documents service:

# Windows users, see Modifying the Example Commands for Windows 
$ curl -X PUT -T ./example.xml --anyauth --user user:password \
  'http://localhost:8000/LATEST/documents?uri=/xml/example.xml&txid=3148548124558550433'

Updates associated with an explicit transaction are visible to other requests executed within the same transaction, but they are not visible outside the transaction until the transaction is committed. See Committing or Rolling Back a Transaction.

The database context in which you evaluate the request must be the same as the database context in which the transaction was created.

Committing or Rolling Back a Transaction

To commit a transaction created by making a POST request to the /transactions service, send a POST request to the /transactions/{txid} service with a URL of the form:

http://host:port/version/transactions/txid?result=outcome

Where txid is a transaction id returned in the Location header of the transaction creation request response, and outcome is either commit or rollback.

MarkLogic Server responds with a 204 when a transaction is successfully committed or rolled back, or if the transaction no longer exists.

Transactions created using the /transactions service should be explicitly commited or rolled back. Failure to commit or rollback the transaction before the request timeout expires causes an automatic rollback. Leaving transactions open unnecessarily potentially holds locks on documents and consume system resources.

Checking Transaction Status

To query the status of a transaction, send a GET request to the /transactions service with a URL of the form:

http://host:port/version/transactions/txid

Where txid is a transaction id returned in the Location header of the transaction creation request response.

MarkLogic Server responds with transaction status information in XML or JSON, depending upon the format requested through the HTTP Accept header or the format URL parameter. The default format is XML. If both the Accept header and the format parameter are set, the format parameter takes precedence.

To request a specific format, set the Accept header to application/json or application/xml, or set the format URL parameter to xml or json. The following example requests JSON output using the Accept header:

# Windows users, see Modifying the Example Commands for Windows 
$ curl -X GET --anyauth --user user:password \
    -H "Accept: application/json" \
    http://localhost:8000/LATEST/transactions/216104635458437451

The XML status information returned in the response takes the following form:

<rapi:transaction-status xmlns:rapi="http://marklogic.com/rest-api">
  <rapi:host>
    <rapi:host-id>1506593501555860493</rapi:host-id>
    <rapi:host-name>somehost</rapi:host-name>
  </rapi:host>
  <rapi:server>
    <rapi:server-id>17994162681305741146</rapi:server-id>
    <rapi:server-name>App-Services</rapi:server-name>
  </rapi:server>
  <rapi:database>
    <rapi:database-id>8896678293064963766</rapi:database-id>
    <rapi:database-name>Documents</rapi:database-name>
  </rapi:database>
  <rapi:transaction-id>216104635458437451</rapi:transaction-id>
  <rapi:transaction-name>client-txn</rapi:transaction-name>
  <rapi:transaction-mode>update</rapi:transaction-mode>
  <rapi:transaction-timestamp>0</rapi:transaction-timestamp>
  <rapi:transaction-state>idle</rapi:transaction-state>
  <rapi:canceled>false</rapi:canceled>
  <rapi:start-time>2012-08-18T17:23:00-07:00</rapi:start-time>
  <rapi:time-limit>600</rapi:time-limit>
  <rapi:max-time-limit>3600</rapi:max-time-limit>
  <rapi:user>7071164303237443533</rapi:user>
  <rapi:admin>true</rapi:admin>
</rapi:transaction-status>

The JSON status information returned in the response takes the following form:

{
  "rapi:transaction-status": {
    "rapi:host": {
      "rapi:host-id": "1506593501555860493",
      "rapi:host-name": "somehost"
    },
    "rapi:server": {
      "rapi:server-id": "17994162681305741146",
      "rapi:server-name": "App-Services"
    },
    "rapi:database": {
      "rapi:database-id": "8896678293064963766",
      "rapi:database-name": "Documents"
    },
    "rapi:transaction-id": "216104635458437451",
    "rapi:transaction-name": "client-txn",
    "rapi:transaction-mode": "update",
    "rapi:transaction-timestamp": "0",
    "rapi:transaction-state": "idle",
    "rapi:canceled": "false",
    "rapi:start-time": "2012-08-18T17:23:00-07:00",
    "rapi:time-limit": "600",
    "rapi:max-time-limit": "3600",
    "rapi:user": "7071164303237443533",
    "rapi:admin": "true"
  }
}

You can also check transaction status using the Admin Interface or xdmp:host-status.

Managing Transactions When Using a Load Balancer

This section applies only to client applications that use multi-statement (multi-request) transactions and interact with a MarkLogic Server cluster through a load balancer. Requests that include a transaction id (txid) request parameter are part of a multi-statement transaction.

When you use a load balancer, it is possible for requests from your application to MarkLogic Server to be routed to different hosts, even within the same session. This has no effect on most interactions with MarkLogic Server, but all requests that are part of the same multi-statement transaction must be routed to the same host within your MarkLogic cluster. This consistent routing through a load balancer is called session affinity.

Most load balancers provide a mechanism that supports session affinity. This usually takes the form of a session cookie that originates on the load balancer. The client acquires the cookie from the load balancer, and passes it on any requests that belong to the session. You can use a load balancer session cookie to preserve session affinity across requests in the same transaction. The exact steps required to configure a load balancer to generate session cookies depends on the load balancer. Consult your load balancer documentation for details.

The following steps describe to use load balancer cookies to preserve session affinity across requests in the same transaction. A graphical representation of this process follows.

  1. Create a multi-statement transaction.
    1. Send a POST request to the /transactions service. The load balancer directs the request to some host in your MarkLogic cluster.
    2. The response from MarkLogic includes a transaction id in the Location header, and the load balancer adds a session cookie. The client application caches the transaction id and session cookie for use on subsequent requests in the same transaction.
  2. Perform operations in the context of the multi-statement transaction.
    1. Send a request to evaluate as part of the transaction, such as a document insertion. Include the transaction id (as a request parameter) and session cookie in your request. The load balancer uses the cookie to direct the request to the same host that originally created the transaction.
    2. MarkLogic responds without inculding any cookies, but the load balancer adds a session cookie.
  3. When ready, close the transaction by committing or rolling back.
    1. Send a POST request to the /transactions/{txid} service that includes the transaction id (in the URL) and session cookie.
    2. MarkLogic closes the transaction and responds with no cookies. The load balancer adds a session cookie. The client application discards the cached transaction id and, usually, the session cookie because the transaction is no longer valid.

The following diagram illustrates the steps described above. The steps in the diagram correspond to the steps in the procedure. The transaction id is represented in the diagram by tid.

The load balancer attaches a session cookie to responses to all REST Client API requests, but your application is only required to pass it back as part of a multi-statement transaction operation.

A REST Client API application can use a session cookie beyond the boundaries of a single multi-statement transaction by attaching the session cookie to other requests. However, most operations do not require session affinity. Omitting the session cookie from requests that are not part of a multi-statement transaction enables the load balancer to distribute work across your MarkLogic cluster more effectively.

You can have multiple multi-statement transactions open concurrently, and you can intermix single-statement transaction requests and multi-statement transaction requests, as long as you preserve the correct association between a transaction id and its session cookie in the multi-statement transaction requests.

You must not send a request that includes a transaction id for one transaction with a session cookie associated with a different one. Some HTTP connection pooling implementations may not properly handle session cookies. For example, a pooled connection might return a cookie that is not the correct one for the transaction you are trying to use.

« Previous chapter
Next chapter »