Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions .github/workflows/docs-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Docs Preview

on:
pull_request:
paths:
- 'src/**'
- 'tools/site_src/**'

jobs:
docs-preview:
name: docs-preview
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
statuses: write
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
6.x
8.x
9.x

- run: dotnet build
- run: dotnet tool update -g docfx
- run: docfx tools/site_src/docfx.json

- name: Deploy to Netlify
uses: nwtgck/actions-netlify@v3
with:
publish-dir: _site
github-token: ${{ secrets.GITHUB_TOKEN }}
deploy-message: "PR #${{ github.event.pull_request.number }} - ${{ github.event.pull_request.title }}"
enable-pull-request-comment: true
enable-commit-comment: false
overwrites-pull-request-comment: true
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
timeout-minutes: 5
Comment thread Fixed
30 changes: 30 additions & 0 deletions src/NATS.Client.JetStream/INatsJSConsumer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@ public interface INatsJSConsumer
/// <summary>
/// Consumer info object as retrieved from NATS JetStream server at the time this object was created, updated or refreshed.
/// </summary>
/// <remarks>
/// <para>
/// <b>Warning:</b> Avoid calling <see cref="RefreshAsync"/> or <see cref="INatsJSContext.GetConsumerAsync"/> repeatedly in a loop
/// to refresh this property. Each call issues a <c>$JS.API.CONSUMER.INFO</c> request to the server, which can cause
/// significant load on the NATS cluster at scale, lead to API timeouts, and degrade overall system performance.
/// </para>
/// <para>
/// Instead, prefer using <see cref="INatsJSMsg{T}.Metadata"/>, when available, on each received message. When
/// <see cref="INatsJSMsg{T}.Metadata"/> is not <c>null</c>, it exposes
/// <see cref="NatsJSMsgMetadata.NumPending"/>, <see cref="NatsJSMsgMetadata.NumDelivered"/>,
/// <see cref="NatsJSMsgMetadata.Sequence"/>, and <see cref="NatsJSMsgMetadata.Timestamp"/>
/// without requiring a server round-trip. Callers should check that <c>Metadata</c> is not <c>null</c> before
/// accessing these properties.
/// </para>
/// </remarks>
ConsumerInfo Info { get; }

/// <summary>
Expand Down Expand Up @@ -79,6 +94,21 @@ IAsyncEnumerable<INatsJSMsg<T>> FetchAsync<T>(
/// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the API call.</param>
/// <exception cref="NatsJSException">There was an issue retrieving the response.</exception>
/// <exception cref="NatsJSApiException">Server responded with an error.</exception>
/// <remarks>
/// <para>
/// <b>Warning:</b> This method issues a <c>$JS.API.CONSUMER.INFO</c> request to the server on every call.
/// Calling it frequently (e.g., in a message-processing loop or on a short timer) can cause significant load
/// on the NATS cluster, lead to API timeouts, and degrade performance for all clients.
/// </para>
/// <para>
/// For tracking consumer progress (e.g., pending message count, sequence numbers, or delivery attempts),
/// use <see cref="INatsJSMsg{T}.Metadata"/> on each received message instead. Note that
/// <see cref="INatsJSMsg{T}.Metadata"/> is nullable and should be checked for <c>null</c> before accessing
/// its properties. When non-null, it provides <see cref="NatsJSMsgMetadata.NumPending"/>,
/// <see cref="NatsJSMsgMetadata.NumDelivered"/>, <see cref="NatsJSMsgMetadata.Sequence"/>, and
/// <see cref="NatsJSMsgMetadata.Timestamp"/> without requiring a server round-trip.
/// </para>
Comment thread
mtmk marked this conversation as resolved.
/// </remarks>
ValueTask RefreshAsync(CancellationToken cancellationToken = default);

/// <summary>
Expand Down
20 changes: 20 additions & 0 deletions src/NATS.Client.JetStream/INatsJSContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,26 @@ ValueTask<INatsJSConsumer> UpdateConsumerAsync(
/// <exception cref="NatsJSApiException">Server responded with an error.</exception>
/// <exception cref="ArgumentException">The <paramref name="stream"/> name is invalid.</exception>
/// <exception cref="ArgumentNullException">The <paramref name="stream"/> name is <c>null</c>.</exception>
/// <remarks>
/// <para>
/// <b>Warning:</b> This method issues a <c>$JS.API.CONSUMER.INFO</c> request to the server on every call.
/// Calling it frequently (e.g., in a message-processing loop or on a short timer) can cause significant load
/// on the NATS cluster, lead to API timeouts, and degrade performance for all clients.
/// </para>
/// <para>
/// If you need to track consumer progress at runtime (e.g., pending message count, sequence numbers, or delivery attempts),
/// use <see cref="INatsJSMsg{T}.Metadata"/> on each received message instead. When available, it provides
/// <see cref="NatsJSMsgMetadata.NumPending"/>, <see cref="NatsJSMsgMetadata.NumDelivered"/>,
/// <see cref="NatsJSMsgMetadata.Sequence"/>, and <see cref="NatsJSMsgMetadata.Timestamp"/>
/// without requiring a server round-trip. Note that <see cref="INatsJSMsg{T}.Metadata"/> can be <c>null</c>
/// (for example, if the reply subject cannot be parsed), so callers should always check for <c>null</c> before
/// accessing its properties.
/// </para>
/// <para>
/// Prefer using <see cref="CreateOrUpdateConsumerAsync"/> or <see cref="CreateConsumerAsync"/> to obtain a consumer
/// handle. Reserve this method for cases where you need to retrieve a consumer that was already created separately.
/// </para>
/// </remarks>
ValueTask<INatsJSConsumer> GetConsumerAsync(string stream, string consumer, CancellationToken cancellationToken = default);

/// <summary>
Expand Down
11 changes: 2 additions & 9 deletions src/NATS.Client.JetStream/NatsJSConsumer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ internal NatsJSConsumer(NatsJSContext context, ConsumerInfo info)
_consumer = Info.Name;
}

/// <summary>
/// Consumer info object as retrieved from NATS JetStream server at the time this object was created, updated or refreshed.
/// </summary>
/// <inheritdoc />
public ConsumerInfo Info { get; private set; }

/// <summary>
Expand Down Expand Up @@ -306,12 +304,7 @@ public async IAsyncEnumerable<INatsJSMsg<T>> FetchNoWaitAsync<T>(
}
}

/// <summary>
/// Retrieve the consumer info from the server and update this consumer.
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the API call.</param>
/// <exception cref="NatsJSException">There was an issue retrieving the response.</exception>
/// <exception cref="NatsJSApiException">Server responded with an error.</exception>
/// <inheritdoc />
public async ValueTask RefreshAsync(CancellationToken cancellationToken = default) =>
Info = await _context.JSRequestResponseAsync<object, ConsumerInfo>(
subject: $"{_context.Opts.Prefix}.CONSUMER.INFO.{_stream}.{_consumer}",
Expand Down
12 changes: 1 addition & 11 deletions src/NATS.Client.JetStream/NatsJSContext.Consumers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,7 @@ public async ValueTask<INatsJSConsumer> UpdateConsumerAsync(
return await CreateOrUpdateConsumerInternalAsync(stream, config, ConsumerCreateAction.Update, cancellationToken);
}

/// <summary>
/// Gets consumer information from the server and creates a NATS JetStream consumer <see cref="NatsJSConsumer"/>.
/// </summary>
/// <param name="stream">Stream name where consumer is associated to.</param>
/// <param name="consumer">Consumer name.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the API call.</param>
/// <returns>The NATS JetStream consumer object which can be used retrieving data from the stream.</returns>
/// <exception cref="NatsJSException">There was an issue retrieving the response.</exception>
/// <exception cref="NatsJSApiException">Server responded with an error.</exception>
/// <exception cref="ArgumentException">The <paramref name="stream"/> name is invalid.</exception>
/// <exception cref="ArgumentNullException">The <paramref name="stream"/> name is <c>null</c>.</exception>
/// <inheritdoc />
public async ValueTask<INatsJSConsumer> GetConsumerAsync(string stream, string consumer, CancellationToken cancellationToken = default)
{
ThrowIfInvalidStreamName(stream);
Expand Down
Loading