package com.atlassian.bitbucket.mesh.throttle;

import com.atlassian.bitbucket.mesh.execution.ExecutionContext;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.ThreadSafe;

/**
 * A ticket to access a {@link #getResource named} resource. When the resource is no longer needed, the ticket
 * holder should {@link #close() close} their ticket, allowing another request to acquire it. The preferred approach
 * for this is to use a {@code try}-with-resources block:
 * <pre><code>
 *     try (Ticket ticket = throttleService.acquireTicket("scm-command")) {
 *         //Do work, knowing the ticket will always be closed
 *     }
 * </code></pre>
 * <p>
 * Note: The maximum duration for a ticket is scoped to the surrounding {@link ExecutionContext}. The system
 * <i>forcibly releases</i> any tickets which are still held at the end of that bounding operation. This is done to
 * prevent resource starvation due to "lost" tickets, which are never otherwise released by their acquiring code.
 * <p>
 * <b>Note:</b> Tickets are thread-safe, and can passed across threads. Acquiring a ticket on one thread and releasing
 * it on another thread <i>is</i> supported.
 *
 * @see ThrottleService
 */
@ThreadSafe
public interface Ticket extends AutoCloseable {

    /**
     * Releases the ticket, indicating the named resource is now available to service another request.
     * <p>
     * The system automatically releases tickets when the surrounding {@link ExecutionContext} ends. However, it is
     * better for ticket holders to release their own tickets after the guarded operation has been performed. This
     * reduces the duration for which the ticket is held, allowing other code to acquire the ticket more readily.
     */
    @Override
    void close();

    /**
     * Retrieves the resource to which this ticket grants access.
     *
     * @return the resource
     */
    @Nonnull
    ThrottledResource getResource();
}
