Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
451fad0
Scheduled jobs wip
benjaminpetit Oct 10, 2025
4b0672f
Address comments
benjaminpetit Oct 14, 2025
e75606e
Add README
benjaminpetit Oct 14, 2025
0039ab1
Remove ShardId from interface
benjaminpetit Oct 14, 2025
ba4dc2c
Split extensions
benjaminpetit Oct 14, 2025
1df4b02
Add metadata
benjaminpetit Oct 16, 2025
cb4edde
Decouple extension
benjaminpetit Oct 16, 2025
6c5a85e
More robust test
benjaminpetit Oct 16, 2025
e8871b0
Move context
benjaminpetit Oct 17, 2025
cb39739
Retry wip
benjaminpetit Oct 17, 2025
b7f36dd
Listen to cluster changes
benjaminpetit Oct 23, 2025
2ee5990
wip
benjaminpetit Oct 23, 2025
5b28fce
Add metadata
benjaminpetit Oct 23, 2025
7dfcfd9
Add metadata test
benjaminpetit Oct 23, 2025
5cb8609
Add cancellation test
benjaminpetit Oct 23, 2025
5329033
Add comments
benjaminpetit Oct 23, 2025
45df0eb
Mark test as skippable
benjaminpetit Oct 24, 2025
281f800
Add logging to AzureStorageJobShardManager
benjaminpetit Oct 24, 2025
9be56be
Plumb job cancellation
benjaminpetit Oct 24, 2025
7194243
More consistent naming
benjaminpetit Oct 24, 2025
0643e8c
Fix retry
benjaminpetit Oct 24, 2025
4545d02
Add comments to InMemoryJobQueue and some unit tests
benjaminpetit Oct 24, 2025
3a8807c
Add tests and fix AzureStorageJobShardManager
benjaminpetit Oct 24, 2025
4248b9e
Enable basic parrallelism limit on shard processing
benjaminpetit Oct 24, 2025
72b9275
keep track of running shards
benjaminpetit Oct 24, 2025
79d6ac5
Add logs and comments to LocalScheduledJobManager
benjaminpetit Oct 24, 2025
b576c61
Merge remote-tracking branch 'dotnet/main' into wip/scheduled-jobs
benjaminpetit Oct 24, 2025
2008fcc
Add READMEs
benjaminpetit Oct 24, 2025
2964e3a
Add READMEs
benjaminpetit Oct 28, 2025
de69620
Update src/Orleans.ScheduledJobs/Hosting/ScheduledJobsOptions.cs
ReubenBond Oct 28, 2025
026caaa
Update src/Orleans.ScheduledJobs/InMemoryJobQueue.cs
ReubenBond Oct 28, 2025
e90f6b8
Apply suggestions from code review
benjaminpetit Oct 29, 2025
fc10282
Add Cancellation tokens to LocalScheduledJobManager
benjaminpetit Oct 30, 2025
8b8a416
Remove default values in JobShard
benjaminpetit Oct 30, 2025
d09874c
Switch from line-based format to netstring format for blob operations
benjaminpetit Oct 30, 2025
7ed5369
Refactor JobShard
benjaminpetit Oct 30, 2025
e3a021b
Add membership version in AzureStorageJobShard
benjaminpetit Oct 30, 2025
98fa1ca
Refactor storage operations to use Channel for single-threaded writes…
benjaminpetit Oct 30, 2025
2091124
Refactor job execution to run concurrently
benjaminpetit Oct 30, 2025
f829bd9
Split LocalScheduledJobManager into separate files for better readabi…
benjaminpetit Oct 30, 2025
616e488
Move ILocalScheduledJobManager interface to its own file
benjaminpetit Oct 30, 2025
c5d41da
Merge branch 'wip/scheduled-jobs' of https://github.com/benjaminpetit…
benjaminpetit Oct 30, 2025
cee9969
Refactor job scheduling methods to use TryScheduleJobAsync for improv…
benjaminpetit Oct 30, 2025
e412923
Very simplistic concurrency control on shard creation
benjaminpetit Oct 30, 2025
bedf374
Enhance IScheduledJobReceiverExtension with improved logging and docu…
benjaminpetit Oct 30, 2025
73cba74
Update ScheduledJobTests and InMemoryJobQueueTests to use UtcNow for …
benjaminpetit Oct 30, 2025
4ee03f3
Refactor shard management to simplify task handling and ensure proper…
benjaminpetit Oct 30, 2025
ede6b13
Refactor AssignJobShardsAsync to improve owner/creator status checks
benjaminpetit Oct 30, 2025
329f75d
Clarify shard start-time naming and logging; update defaults and proj…
benjaminpetit Oct 30, 2025
2bb5172
Fix netstring encoding/delimiter and format MembershipVersion invaria…
benjaminpetit Oct 30, 2025
9ca1cb4
Scale default MaxConcurrentJobsPerSilo by CPU count
benjaminpetit Oct 30, 2025
c440fae
Rename GetJobCount to GetJobCountAsync and IsComplete to IsAddingComp…
benjaminpetit Oct 30, 2025
c2f4c70
Return removal result from CancelJob and update tests
benjaminpetit Oct 30, 2025
4f68cc0
Return removal result from RemoveJobAsync and update cancel flow & tests
benjaminpetit Oct 30, 2025
d4c5cd8
Consolidate scheduling API: merge ScheduleJobWithMetadataAsync into S…
benjaminpetit Oct 30, 2025
043fffd
Add cross-grain scheduling test and SchedulerGrain; make ScheduleJobA…
benjaminpetit Oct 30, 2025
db44fad
Add job retry test and RetryTestGrain
benjaminpetit Oct 30, 2025
c5498d6
Extract scheduled job test logic into ScheduledJobTestsRunner and add…
benjaminpetit Oct 30, 2025
069fe77
Add Azure Blob Storage hosting integration for scheduled jobs
benjaminpetit Oct 30, 2025
c6e8cc8
Add AzureStorageScheduledJobTests to run scheduled job tests against …
benjaminpetit Oct 30, 2025
6a05384
Remove stuff
benjaminpetit Oct 30, 2025
f72d4c9
Remove stuff
benjaminpetit Oct 30, 2025
156659a
Add CancellationToken to IClusterMembershipService.Refresh and propag…
benjaminpetit Oct 31, 2025
560aae9
Add blob-prefix support to AzureStorageJobShardManager and update tests
benjaminpetit Oct 31, 2025
29a0dec
Replace TaskCanceledException with OperationCanceledException
benjaminpetit Oct 31, 2025
e23e1ac
Cancel pending storage operations on shutdown
benjaminpetit Oct 31, 2025
5b00a75
Use MembershipVersion.Value for blob metadata; rename/add InMemorySch…
benjaminpetit Oct 31, 2025
173921a
Rename LocalScheduledJobManager system target grain type to "job-mana…
benjaminpetit Oct 31, 2025
1413e15
Replace IScheduledJob interface with ScheduledJob concrete type
benjaminpetit Oct 31, 2025
10e0565
Fix shard bucketing, correct shard assignment window, and add options…
benjaminpetit Oct 31, 2025
7a5a526
Gracefully stop shard storage processor; fix caching and metadata par…
benjaminpetit Oct 31, 2025
7446b8d
Dispose newly-created shard on ownership conflict; remove unused blob…
benjaminpetit Oct 31, 2025
5199685
Remove unused Microsoft.CodeAnalysis using; clarify shard-too-new com…
benjaminpetit Oct 31, 2025
12d694e
Introduce NetstringEncoder utility and tests; use it in AzureStorageJ…
benjaminpetit Oct 31, 2025
0655f6a
Fix bad rename
benjaminpetit Oct 31, 2025
fc15a75
Replace NetstringEncoder with NetstringJsonSerializer; update usages …
benjaminpetit Oct 31, 2025
4ac0c41
Make NetstringJsonSerializer stream-based with pooled buffers; update…
benjaminpetit Nov 3, 2025
fc6ba4d
Batch Azure Storage append operations; add batching options and tests
benjaminpetit Nov 3, 2025
5b9ba88
Rename RegisterShard -> CreateShardAsync and simplify ownership behavior
benjaminpetit Nov 3, 2025
fa3eb54
Make InMemoryJobQueue synchronization and enumeration safer
benjaminpetit Nov 4, 2025
bc26774
Add periodic shard checker and shard activation buffer option
benjaminpetit Nov 4, 2025
46fe7d0
Centralize shard lifecycle in manager; add periodic shard checker and…
benjaminpetit Nov 4, 2025
8ba69f4
Unify StorageOperation completion handling and make shutdown cancellable
benjaminpetit Nov 4, 2025
e20e7a8
Remove Creator metadata and simplify ownership/ID handling; add blob-…
benjaminpetit Nov 4, 2025
9e42a9b
Add structured logging to AzureStorageJobShard and propagate ILoggerF…
benjaminpetit Nov 4, 2025
00a772e
Make InMemoryJobQueue internal, add InternalsVisibleTo
benjaminpetit Nov 4, 2025
e07538f
Drop explicit '= false' initializer for IsAddingCompleted property in…
benjaminpetit Nov 4, 2025
5c781dc
wip
benjaminpetit Nov 4, 2025
c0f937b
Split test into a runner for reusability; make them pass faster; make
benjaminpetit Nov 4, 2025
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
6 changes: 4 additions & 2 deletions Orleans.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<Project Path="src/Orleans.Persistence.Memory/Orleans.Persistence.Memory.csproj" />
<Project Path="src/Orleans.Reminders/Orleans.Reminders.csproj" />
<Project Path="src/Orleans.Runtime/Orleans.Runtime.csproj" />
<Project Path="src/Orleans.ScheduledJobs/Orleans.ScheduledJobs.csproj" Id="ab4cc723-b3cf-4c32-be4c-1a180a49797c" />
<Project Path="src/Orleans.Sdk/Orleans.Sdk.csproj" />
<Project Path="src/Orleans.Serialization.Abstractions/Orleans.Serialization.Abstractions.csproj" />
<Project Path="src/Orleans.Serialization.FSharp/Orleans.Serialization.FSharp.csproj" />
Expand Down Expand Up @@ -76,6 +77,7 @@
<Project Path="src/Azure/Orleans.Persistence.Cosmos/Orleans.Persistence.Cosmos.csproj" />
<Project Path="src/Azure/Orleans.Reminders.AzureStorage/Orleans.Reminders.AzureStorage.csproj" />
<Project Path="src/Azure/Orleans.Reminders.Cosmos/Orleans.Reminders.Cosmos.csproj" />
<Project Path="src/Azure/Orleans.ScheduledJobs.AzureStorage/Orleans.ScheduledJobs.AzureStorage.csproj" Id="5bbb1058-9ab2-44e9-b237-49f5b6bee151" />
<Project Path="src/Azure/Orleans.Streaming.AzureStorage/Orleans.Streaming.AzureStorage.csproj" />
<Project Path="src/Azure/Orleans.Streaming.EventHubs/Orleans.Streaming.EventHubs.csproj" />
<Project Path="src/Azure/Orleans.Transactions.AzureStorage/Orleans.Transactions.AzureStorage.csproj" />
Expand All @@ -84,7 +86,7 @@
<Project Path="src/Cassandra/Orleans.Clustering.Cassandra/Orleans.Clustering.Cassandra.csproj" />
</Folder>
<Folder Name="/src/Extensions/NATS/">
<Project Path="src\Orleans.Streaming.NATS\Orleans.Streaming.NATS.csproj" Type="Classic C#" />
<Project Path="src\Orleans.Streaming.NATS\Orleans.Streaming.NATS.csproj" />
</Folder>
<Folder Name="/src/Extensions/Redis/">
<Project Path="src/Redis/Orleans.Clustering.Redis/Orleans.Clustering.Redis.csproj" />
Expand Down Expand Up @@ -133,7 +135,7 @@
<Project Path="test/Extensions/TesterAdoNet/Tester.AdoNet.csproj" />
<Project Path="test/Extensions/TesterAzureUtils/Tester.AzureUtils.csproj" />
<Project Path="test/Extensions/TesterZooKeeperUtils/Tester.ZooKeeperUtils.csproj" />
<Project Path="test\Extensions\NATS.Tests\NATS.Tests.csproj" Type="Classic C#" />
<Project Path="test\Extensions\NATS.Tests\NATS.Tests.csproj" />
</Folder>
<Folder Name="/test/Grains/">
<Project Path="test/Grains/TestFSharp/TestFSharp.fsproj" />
Expand Down
149 changes: 149 additions & 0 deletions src/Azure/Orleans.ScheduledJobs.AzureStorage/AzureStorageJobShard.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using Azure;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Blobs.Specialized;
using Orleans.Runtime;

namespace Orleans.ScheduledJobs.AzureStorage;

internal sealed class AzureStorageJobShard : JobShard
{
internal AppendBlobClient BlobClient { get; init; }
internal ETag? ETag { get; private set; }

private InMemoryJobQueue _jobQueue;
private int _jobCount = 0;
Comment thread
benjaminpetit marked this conversation as resolved.
Outdated

public AzureStorageJobShard(string id, DateTimeOffset startTime, DateTimeOffset endTime, AppendBlobClient blobClient)
: base(id, startTime, endTime)
{
BlobClient = blobClient;
_jobQueue = new InMemoryJobQueue();
}

public override ValueTask<int> GetJobCount()
{
return ValueTask.FromResult(_jobCount);
}

public override IAsyncEnumerable<IScheduledJob> ConsumeScheduledJobsAsync()
{
return _jobQueue;
}

public override async Task RemoveJobAsync(string jobId)
{
var operation = JobOperation.CreateRemoveOperation(jobId);
Comment thread
benjaminpetit marked this conversation as resolved.
await AppendOperation(operation);
_jobQueue.CancelJob(jobId);
_jobCount--;
}

public override async Task<IScheduledJob> ScheduleJobAsync(GrainId target, string jobName, DateTimeOffset dueTime)
{
if (IsComplete)
throw new InvalidOperationException("Cannot schedule job on a complete shard.");

var jobId = Guid.NewGuid().ToString();
var operation = JobOperation.CreateAddOperation(jobId, jobName, dueTime, target);
await AppendOperation(operation);
_jobCount++;
var job = new ScheduledJob
{
Id = jobId,
Name = jobName,
DueTime = dueTime,
TargetGrainId = target,
ShardId = Id
};
_jobQueue.Enqueue(job);
return job;
}

private async Task AppendOperation(JobOperation operation)
{
var content = BinaryData.FromObjectAsJson(operation).ToString() + Environment.NewLine;
Comment thread
benjaminpetit marked this conversation as resolved.
Outdated
using var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(content));
var result = await BlobClient.AppendBlockAsync(
Comment thread
ReubenBond marked this conversation as resolved.
Outdated
stream,
new AppendBlobAppendBlockOptions { Conditions = new AppendBlobRequestConditions { IfMatch = ETag } });
ETag = result.Value.ETag;
}

public async ValueTask InitializeAsync()
{
if (ETag is not null) return; // already initialized

// Load existing blob
var response = await BlobClient.DownloadAsync();
using var stream = response.Value.Content;
using var reader = new StreamReader(stream);

// Rebuild state by replaying operations
var dictionary = new Dictionary<string, JobOperation>();
while (!reader.EndOfStream)
{
var line = await reader.ReadLineAsync();
if (string.IsNullOrWhiteSpace(line)) continue;
var operation = JsonSerializer.Deserialize<JobOperation>(line);
switch (operation.Type)
{
case JobOperation.OperationType.Add:
dictionary[operation.Id] = operation;
break;
case JobOperation.OperationType.Remove:
dictionary.Remove(operation.Id);
break;
}
}
// Rebuild the priority queue
foreach (var op in dictionary.Values)
{
_jobQueue.Enqueue(new ScheduledJob
{
Id = op.Id,
Name = op.Name!,
DueTime = op.DueTime!.Value,
TargetGrainId = op.TargetGrainId!.Value,
ShardId = Id
});
}
_jobCount = dictionary.Count;

ETag = response.Value.Details.ETag;
}

public override Task MarkAsComplete()
{
IsComplete = true;
_jobQueue.MarkAsComplete();
return Task.CompletedTask;
}
}

internal struct JobOperation
{
public enum OperationType
{
Add,
Remove
}

public OperationType Type { get; init; }

public string Id { get; init; }
public string? Name { get; init; }
public DateTimeOffset? DueTime { get; init; }
public GrainId? TargetGrainId { get; init; }

public static JobOperation CreateAddOperation(string id, string name, DateTimeOffset dueTime, GrainId targetGrainId) =>
new() { Type = OperationType.Add, Id = id, Name = name, DueTime = dueTime, TargetGrainId = targetGrainId };

public static JobOperation CreateRemoveOperation(string id) =>
new() { Type = OperationType.Remove, Id = id };
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Azure;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Blobs.Specialized;
using Microsoft.Extensions.Options;
using Orleans.Runtime;

namespace Orleans.ScheduledJobs.AzureStorage;

public sealed class AzureStorageJobShardManager : JobShardManager
{
private readonly BlobServiceClient _blobServiceClient;
private readonly string _containerName;
private BlobContainerClient _client = null!;
private readonly TimeSpan _maxShardDuration;
private readonly IClusterMembershipService _clusterMembership;

public AzureStorageJobShardManager(BlobServiceClient client, string containerName, TimeSpan maxShardDuration, IClusterMembershipService clusterMembership)
{
_blobServiceClient = client;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we ever need to support multiple concurrent accounts? For throughput / failover / etc?

_containerName = containerName;
_maxShardDuration = maxShardDuration;
_clusterMembership = clusterMembership;
}

public AzureStorageJobShardManager(IOptions<AzureStorageJobShardOptions> options, IClusterMembershipService clusterMembership)
: this(options.Value.BlobServiceClient, options.Value.ContainerName, options.Value.MaxShardDuration, clusterMembership)
{
}

public override async Task<List<JobShard>> GetJobShardsAsync(SiloAddress siloAddress, DateTimeOffset maxDateTime)
{
await InitializeIfNeeded();
var blobs = _client.GetBlobsAsync(traits: BlobTraits.Metadata);
var result = new List<JobShard>();
await foreach (var blob in blobs)
{
// Get the owner of the shard
var (owner, minDueTime, maxDueTime) = ParseMetadata(blob.Metadata);

if (minDueTime > maxDateTime)
Comment thread
benjaminpetit marked this conversation as resolved.
Outdated
{
Comment thread
benjaminpetit marked this conversation as resolved.
// This shard is too new, stop there
break;
}

if (owner == null || _clusterMembership.CurrentSnapshot.GetSiloStatus(owner) == SiloStatus.Dead)
{
// The owner is dead or unknown, we can take over this shard
var blobClient = _client.GetAppendBlobClient(blob.Name);
var metadata = blob.Metadata;
metadata["Owner"] = siloAddress.ToParsableString();
try
{
await blobClient.SetMetadataAsync(metadata, conditions: new BlobRequestConditions { IfMatch = blob.Properties.ETag });
}
catch (RequestFailedException)
{
// Someone else took over the shard
continue;
}
var shard = new AzureStorageJobShard(blob.Name, minDueTime, maxDueTime, blobClient);
await shard.InitializeAsync();
await shard.MarkAsComplete();
Comment thread
benjaminpetit marked this conversation as resolved.
Outdated
result.Add(shard);
}
}
return result;
}

public override async Task<JobShard> RegisterShard(SiloAddress siloAddress, DateTimeOffset minDueTime, DateTimeOffset maxDueTime, IDictionary<string, string> metadata)
{
await InitializeIfNeeded();
for (var i = 0;; i++) // TODO limit the number of attempts
Comment thread
ReubenBond marked this conversation as resolved.
Outdated
{
var shardId = $"{minDueTime:yyyyMMddHHmm}-{siloAddress.ToParsableString()}-{i}";
var blobClient = _client.GetAppendBlobClient(shardId);
var metadataInfo = CreateMetadata(siloAddress, minDueTime, maxDueTime);
try
{
var response = await blobClient.CreateIfNotExistsAsync(metadata: metadataInfo);
if (response == null)
{
// Blob already exists, try again with a different name
continue;
}
}
catch (RequestFailedException)
{
if (i > 100) throw; // Prevent infinite loop
// Blob already exists, try again with a different name
continue;
}
var shard = new AzureStorageJobShard(shardId, minDueTime, maxDueTime, blobClient);
await shard.InitializeAsync();
return shard;
}
}

public override async Task UnregisterShard(SiloAddress siloAddress, JobShard shard)
{
var azureShard = shard as AzureStorageJobShard ?? throw new ArgumentException("Shard is not an AzureStorageJobShard", nameof(shard));
var conditions = new BlobRequestConditions { IfMatch = azureShard.ETag };
var count = await shard.GetJobCount();
var properties = await azureShard.BlobClient.GetPropertiesAsync(conditions);
if (count > 0)
{
// There are still jobs in the shard, unregister it
Comment thread
benjaminpetit marked this conversation as resolved.
var metadata = properties.Value.Metadata;
var (owner, _, _) = ParseMetadata(metadata);

if (owner != siloAddress)
throw new InvalidOperationException("Cannot unregister a shard owned by another silo");

metadata.Remove("Owner");
var response = await azureShard.BlobClient.SetMetadataAsync(metadata, conditions);
}
else
{
// No jobs left, we can delete the shard
await azureShard.BlobClient.DeleteIfExistsAsync(conditions: conditions);
}
}

private ValueTask InitializeIfNeeded()
{
if (_client != null) return ValueTask.CompletedTask;

_client = _blobServiceClient.GetBlobContainerClient(_containerName);
_client.CreateIfNotExists();
Comment thread
benjaminpetit marked this conversation as resolved.
Outdated
return ValueTask.CompletedTask;
}

private static Dictionary<string, string> CreateMetadata(SiloAddress siloAddress, DateTimeOffset minDueTime, DateTimeOffset maxDueTime)
{
return new Dictionary<string, string>
{
{ "Owner", siloAddress.ToParsableString() },
{ "MinDueTime", minDueTime.ToString("o") },
{ "MaxDueTime", maxDueTime.ToString("o") }
};
}

private static (SiloAddress? owner, DateTime minDueTime, DateTime maxDueTime) ParseMetadata(IDictionary<string, string> metadata)
{
var owner = metadata.TryGetValue("Owner", out var ownerStr) ? SiloAddress.FromParsableString(ownerStr) : null;
var minDueTime = metadata.TryGetValue("MinDueTime", out var minDueTimeStr) && DateTime.TryParse(minDueTimeStr, out var minDt) ? minDt : DateTime.MinValue;
var maxDueTime = metadata.TryGetValue("MaxDueTime", out var maxDueTimeStr) && DateTime.TryParse(maxDueTimeStr, out var maxDt) ? maxDt : DateTime.MaxValue;
return (owner, minDueTime.ToUniversalTime(), maxDueTime.ToUniversalTime());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using Azure.Storage.Blobs;

namespace Orleans.ScheduledJobs.AzureStorage;

public class AzureStorageJobShardOptions
{
/// <summary>
/// The maximum duration of a job shard.
/// </summary>
public TimeSpan MaxShardDuration { get; set; } = TimeSpan.FromHours(1);

/// <summary>
/// Gets or sets the <see cref="BlobServiceClient"/> instance used to store job shards.
/// </summary>
public BlobServiceClient BlobServiceClient { get; set; } = null!;

/// <summary>
/// Gets or sets the name of the container used to store scheduled jobs.
/// </summary>
public string ContainerName { get; set; } = "scheduled-jobs";
Comment thread
benjaminpetit marked this conversation as resolved.
Outdated
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageId>Microsoft.Orleans.ScheduledJobs.AzureStorage</PackageId>
<Title>Microsoft Orleans Azure Storage ScheduledJobs Provider</Title>
<Description>Microsoft Orleans reminders provider backed by Azure Storage</Description>
<PackageTags>$(PackageTags) Azure Storage</PackageTags>
<TargetFrameworks>$(DefaultTargetFrameworks)</TargetFrameworks>
<AssemblyName>Orleans.ScheduledJobs.AzureStorage</AssemblyName>
<RootNamespace>Orleans.ScheduledJobs.AzureStorage</RootNamespace>
<OrleansBuildTimeCodeGen>true</OrleansBuildTimeCodeGen>
<DefineConstants>$(DefineConstants);ORLEANS_REMINDERS</DefineConstants>
Comment thread
benjaminpetit marked this conversation as resolved.
Outdated
<Nullable>enable</Nullable>
</PropertyGroup>
Comment thread
benjaminpetit marked this conversation as resolved.

<ItemGroup>
<ProjectReference Include="$(SourceRoot)src\Orleans.Runtime\Orleans.Runtime.csproj" />
<ProjectReference Include="$(SourceRoot)src\Orleans.ScheduledJobs\Orleans.ScheduledJobs.csproj" />
<PackageReference Include="Azure.Core" />
<PackageReference Include="Azure.Storage.Blobs" />
</ItemGroup>

</Project>
1 change: 1 addition & 0 deletions src/Orleans.Core/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
[assembly: InternalsVisibleTo("Orleans.CodeGeneration")]
[assembly: InternalsVisibleTo("Orleans.CodeGeneration.Build")]
[assembly: InternalsVisibleTo("Orleans.Runtime")]
[assembly: InternalsVisibleTo("Orleans.ScheduledJobs")]
[assembly: InternalsVisibleTo("Orleans.Streaming")]
[assembly: InternalsVisibleTo("Orleans.TestingHost")]

Expand Down
Loading
Loading