✨ Publisher rewarding
This commit is contained in:
@@ -9,7 +9,13 @@ public class SocialCreditService(AppDatabase db, ICacheService cache)
|
|||||||
{
|
{
|
||||||
private const string CacheKeyPrefix = "account:credits:";
|
private const string CacheKeyPrefix = "account:credits:";
|
||||||
|
|
||||||
public async Task<SnSocialCreditRecord> AddRecord(string reasonType, string reason, double delta, Guid accountId)
|
public async Task<SnSocialCreditRecord> AddRecord(
|
||||||
|
string reasonType,
|
||||||
|
string reason,
|
||||||
|
double delta,
|
||||||
|
Guid accountId,
|
||||||
|
Instant? expiredAt
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var record = new SnSocialCreditRecord
|
var record = new SnSocialCreditRecord
|
||||||
{
|
{
|
||||||
@@ -17,6 +23,7 @@ public class SocialCreditService(AppDatabase db, ICacheService cache)
|
|||||||
Reason = reason,
|
Reason = reason,
|
||||||
Delta = delta,
|
Delta = delta,
|
||||||
AccountId = accountId,
|
AccountId = accountId,
|
||||||
|
ExpiredAt = expiredAt
|
||||||
};
|
};
|
||||||
db.SocialCreditRecords.Add(record);
|
db.SocialCreditRecords.Add(record);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
@@ -61,7 +68,8 @@ public class SocialCreditService(AppDatabase db, ICacheService cache)
|
|||||||
{
|
{
|
||||||
await db.AccountProfiles
|
await db.AccountProfiles
|
||||||
.Where(p => p.AccountId == accountId)
|
.Where(p => p.AccountId == accountId)
|
||||||
.ExecuteUpdateAsync(p => p.SetProperty(v => v.SocialCredits, v => v.SocialCredits - totalDeltaSubtracted));
|
.ExecuteUpdateAsync(p =>
|
||||||
|
p.SetProperty(v => v.SocialCredits, v => v.SocialCredits - totalDeltaSubtracted));
|
||||||
await cache.RemoveAsync($"{CacheKeyPrefix}{accountId}");
|
await cache.RemoveAsync($"{CacheKeyPrefix}{accountId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,29 @@
|
|||||||
using DysonNetwork.Shared.Proto;
|
using DysonNetwork.Shared.Proto;
|
||||||
using Grpc.Core;
|
using Grpc.Core;
|
||||||
|
using NodaTime.Serialization.Protobuf;
|
||||||
|
|
||||||
namespace DysonNetwork.Pass.Credit;
|
namespace DysonNetwork.Pass.Credit;
|
||||||
|
|
||||||
public class SocialCreditServiceGrpc(SocialCreditService creditService) : Shared.Proto.SocialCreditService.SocialCreditServiceBase
|
public class SocialCreditServiceGrpc(SocialCreditService creditService)
|
||||||
|
: Shared.Proto.SocialCreditService.SocialCreditServiceBase
|
||||||
{
|
{
|
||||||
public override async Task<Shared.Proto.SocialCreditRecord> AddRecord(AddSocialCreditRecordRequest request, ServerCallContext context)
|
public override async Task<SocialCreditRecord> AddRecord(AddSocialCreditRecordRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
{
|
{
|
||||||
var accountId = Guid.Parse(request.AccountId);
|
var accountId = Guid.Parse(request.AccountId);
|
||||||
var record = await creditService.AddRecord(
|
var record = await creditService.AddRecord(
|
||||||
request.ReasonType,
|
request.ReasonType,
|
||||||
request.Reason,
|
request.Reason,
|
||||||
request.Delta,
|
request.Delta,
|
||||||
accountId);
|
accountId,
|
||||||
|
request.ExpiredAt.ToInstant()
|
||||||
|
);
|
||||||
|
|
||||||
return record.ToProto();
|
return record.ToProto();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<SocialCreditResponse> GetSocialCredit(GetSocialCreditRequest request, ServerCallContext context)
|
public override async Task<SocialCreditResponse> GetSocialCredit(GetSocialCreditRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
{
|
{
|
||||||
var accountId = Guid.Parse(request.AccountId);
|
var accountId = Guid.Parse(request.AccountId);
|
||||||
var amount = await creditService.GetSocialCredit(accountId);
|
var amount = await creditService.GetSocialCredit(accountId);
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ message AddSocialCreditRecordRequest {
|
|||||||
string reason = 2;
|
string reason = 2;
|
||||||
double delta = 3;
|
double delta = 3;
|
||||||
string account_id = 4; // UUID string
|
string account_id = 4; // UUID string
|
||||||
|
google.protobuf.Timestamp expired_at = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetSocialCreditRequest {
|
message GetSocialCreditRequest {
|
||||||
|
|||||||
@@ -72,6 +72,18 @@ public static class ServiceInjectionHelper
|
|||||||
);
|
);
|
||||||
services.AddSingleton<RemoteRealmService>();
|
services.AddSingleton<RemoteRealmService>();
|
||||||
|
|
||||||
|
services
|
||||||
|
.AddGrpcClient<SocialCreditService.SocialCreditServiceClient>(o => o.Address = new Uri("https://_grpc.pass"))
|
||||||
|
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
|
||||||
|
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
|
||||||
|
);
|
||||||
|
|
||||||
|
services
|
||||||
|
.AddGrpcClient<ExperienceService.ExperienceServiceClient>(o => o.Address = new Uri("https://_grpc.pass"))
|
||||||
|
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler()
|
||||||
|
{ ServerCertificateCustomValidationCallback = (_, _, _, _) => true }
|
||||||
|
);
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Authorization;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NodaTime;
|
using NodaTime;
|
||||||
|
using PublisherMemberRole = DysonNetwork.Shared.Models.PublisherMemberRole;
|
||||||
|
|
||||||
namespace DysonNetwork.Sphere.Publisher;
|
namespace DysonNetwork.Sphere.Publisher;
|
||||||
|
|
||||||
@@ -650,6 +651,27 @@ public class PublisherController(
|
|||||||
return Ok(dict);
|
return Ok(dict);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("{name}/rewards")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult<PublisherService.PublisherRewardPreview>> GetPublisherExpectedReward(
|
||||||
|
string name
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||||
|
var accountId = Guid.Parse(currentUser.Id);
|
||||||
|
|
||||||
|
var publisher = await db.Publishers
|
||||||
|
.Where(p => p.Name == name)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
if (publisher is null) return NotFound();
|
||||||
|
|
||||||
|
if (!await ps.IsMemberWithRole(publisher.Id, accountId, PublisherMemberRole.Viewer))
|
||||||
|
return StatusCode(403, "You are not allowed to view stats data of this publisher.");
|
||||||
|
|
||||||
|
var result = await ps.GetPublisherExpectedReward(publisher.Id);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
public class PublisherFeatureRequest
|
public class PublisherFeatureRequest
|
||||||
{
|
{
|
||||||
[Required] public string Flag { get; set; } = null!;
|
[Required] public string Flag { get; set; } = null!;
|
||||||
@@ -701,4 +723,13 @@ public class PublisherController(
|
|||||||
|
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost("rewards/settle")]
|
||||||
|
[Authorize]
|
||||||
|
[RequiredPermission("maintenance", "publishers.reward.settle")]
|
||||||
|
public async Task<IActionResult> PerformLotteryDraw()
|
||||||
|
{
|
||||||
|
await ps.SettlePublisherRewards();
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
|
using System.Globalization;
|
||||||
using DysonNetwork.Shared.Cache;
|
using DysonNetwork.Shared.Cache;
|
||||||
using DysonNetwork.Shared.Models;
|
using DysonNetwork.Shared.Models;
|
||||||
using DysonNetwork.Shared.Proto;
|
using DysonNetwork.Shared.Proto;
|
||||||
using DysonNetwork.Shared.Registry;
|
using DysonNetwork.Shared.Registry;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NodaTime;
|
using NodaTime;
|
||||||
|
using NodaTime.Serialization.Protobuf;
|
||||||
using PublisherMemberRole = DysonNetwork.Shared.Models.PublisherMemberRole;
|
using PublisherMemberRole = DysonNetwork.Shared.Models.PublisherMemberRole;
|
||||||
using PublisherType = DysonNetwork.Shared.Models.PublisherType;
|
using PublisherType = DysonNetwork.Shared.Models.PublisherType;
|
||||||
|
|
||||||
@@ -12,6 +14,8 @@ namespace DysonNetwork.Sphere.Publisher;
|
|||||||
public class PublisherService(
|
public class PublisherService(
|
||||||
AppDatabase db,
|
AppDatabase db,
|
||||||
FileReferenceService.FileReferenceServiceClient fileRefs,
|
FileReferenceService.FileReferenceServiceClient fileRefs,
|
||||||
|
SocialCreditService.SocialCreditServiceClient socialCredits,
|
||||||
|
ExperienceService.ExperienceServiceClient experiences,
|
||||||
ICacheService cache,
|
ICacheService cache,
|
||||||
RemoteAccountService remoteAccounts
|
RemoteAccountService remoteAccounts
|
||||||
)
|
)
|
||||||
@@ -300,10 +304,12 @@ public class PublisherService(
|
|||||||
|
|
||||||
var postsCount = await db.Posts.Where(e => e.Publisher.Id == publisher.Id).CountAsync();
|
var postsCount = await db.Posts.Where(e => e.Publisher.Id == publisher.Id).CountAsync();
|
||||||
var postsUpvotes = await db.PostReactions
|
var postsUpvotes = await db.PostReactions
|
||||||
.Where(r => r.Post.Publisher.Id == publisher.Id && r.Attitude == Shared.Models.PostReactionAttitude.Positive)
|
.Where(r => r.Post.Publisher.Id == publisher.Id &&
|
||||||
|
r.Attitude == Shared.Models.PostReactionAttitude.Positive)
|
||||||
.CountAsync();
|
.CountAsync();
|
||||||
var postsDownvotes = await db.PostReactions
|
var postsDownvotes = await db.PostReactions
|
||||||
.Where(r => r.Post.Publisher.Id == publisher.Id && r.Attitude == Shared.Models.PostReactionAttitude.Negative)
|
.Where(r => r.Post.Publisher.Id == publisher.Id &&
|
||||||
|
r.Attitude == Shared.Models.PostReactionAttitude.Negative)
|
||||||
.CountAsync();
|
.CountAsync();
|
||||||
|
|
||||||
var stickerPacksId = await db.StickerPacks.Where(e => e.Publisher.Id == publisher.Id).Select(e => e.Id)
|
var stickerPacksId = await db.StickerPacks.Where(e => e.Publisher.Id == publisher.Id).Select(e => e.Id)
|
||||||
@@ -462,4 +468,182 @@ public class PublisherService(
|
|||||||
|
|
||||||
return publishers.ToList();
|
return publishers.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PublisherRewardPreview
|
||||||
|
{
|
||||||
|
public int Experience { get; set; }
|
||||||
|
public int SocialCredits { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PublisherRewardPreview> GetPublisherExpectedReward(Guid publisherId)
|
||||||
|
{
|
||||||
|
var cacheKey = $"publisher:{publisherId}:rewards";
|
||||||
|
var (found, cached) = await cache.GetAsyncWithStatus<PublisherRewardPreview>(cacheKey);
|
||||||
|
if (found)
|
||||||
|
return cached!;
|
||||||
|
|
||||||
|
var now = SystemClock.Instance.GetCurrentInstant();
|
||||||
|
var yesterday = now.InZone(DateTimeZone.Utc).Date.PlusDays(-1);
|
||||||
|
var periodStart = yesterday.AtStartOfDayInZone(DateTimeZone.Utc).ToInstant();
|
||||||
|
var periodEnd = periodStart.Plus(Duration.FromDays(1)).Minus(Duration.FromMilliseconds(1));
|
||||||
|
|
||||||
|
// Get posts stats for this publisher: count, id, exclude content
|
||||||
|
var postsInPeriod = await db.Posts
|
||||||
|
.Where(p => p.PublisherId == publisherId && p.CreatedAt >= periodStart && p.CreatedAt <= periodEnd)
|
||||||
|
.Select(p => new { Id = p.Id, AwardedScore = p.AwardedScore })
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// Get reactions for these posts
|
||||||
|
var postIds = postsInPeriod.Select(p => p.Id).ToList();
|
||||||
|
var reactions = await db.PostReactions
|
||||||
|
.Where(r => postIds.Contains(r.PostId))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
if (postsInPeriod.Count == 0)
|
||||||
|
return new PublisherRewardPreview { Experience = 0, SocialCredits = 0 };
|
||||||
|
|
||||||
|
// Calculate stats
|
||||||
|
var postCount = postsInPeriod.Count;
|
||||||
|
var upvotes = reactions.Count(r => r.Attitude == Shared.Models.PostReactionAttitude.Positive);
|
||||||
|
var downvotes = reactions.Count(r => r.Attitude == Shared.Models.PostReactionAttitude.Negative);
|
||||||
|
var awardScore = postsInPeriod.Sum(p => (double)p.AwardedScore);
|
||||||
|
|
||||||
|
// Each post counts as 100 experiences,
|
||||||
|
// and each point (upvote - downvote + award score * 0.1) count as 10 experiences
|
||||||
|
var netVotes = upvotes - downvotes;
|
||||||
|
var points = netVotes + awardScore * 0.1;
|
||||||
|
var experienceFromPosts = postCount * 100;
|
||||||
|
var experienceFromPoints = (int)(points * 10);
|
||||||
|
var totalExperience = experienceFromPosts + experienceFromPoints;
|
||||||
|
|
||||||
|
var preview = new PublisherRewardPreview
|
||||||
|
{
|
||||||
|
Experience = totalExperience,
|
||||||
|
SocialCredits = (int)(points * 10)
|
||||||
|
};
|
||||||
|
|
||||||
|
await cache.SetAsync(cacheKey, preview, TimeSpan.FromMinutes(5));
|
||||||
|
return preview;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SettlePublisherRewards()
|
||||||
|
{
|
||||||
|
var now = SystemClock.Instance.GetCurrentInstant();
|
||||||
|
var yesterday = now.InZone(DateTimeZone.Utc).Date.PlusDays(-1);
|
||||||
|
var periodStart = yesterday.AtStartOfDayInZone(DateTimeZone.Utc).ToInstant();
|
||||||
|
var periodEnd = periodStart.Plus(Duration.FromDays(1)).Minus(Duration.FromMilliseconds(1));
|
||||||
|
|
||||||
|
// Get posts stats: count, publisher id, exclude content
|
||||||
|
var postsInPeriod = await db.Posts
|
||||||
|
.Where(p => p.CreatedAt >= periodStart && p.CreatedAt <= periodEnd)
|
||||||
|
.Select(p => new { Id = p.Id, PublisherId = p.PublisherId, AwardedScore = p.AwardedScore })
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// Get reactions for these posts
|
||||||
|
var postIds = postsInPeriod.Select(p => p.Id).ToList();
|
||||||
|
var reactions = await db.PostReactions
|
||||||
|
.Where(r => postIds.Contains(r.PostId))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// Group stats by publisher id
|
||||||
|
var postIdToPublisher = postsInPeriod.ToDictionary(p => p.Id, p => p.PublisherId);
|
||||||
|
var publisherStats = postsInPeriod
|
||||||
|
.GroupBy(p => p.PublisherId)
|
||||||
|
.ToDictionary(g => g.Key,
|
||||||
|
g => new
|
||||||
|
{
|
||||||
|
PostCount = g.Count(), Upvotes = 0, Downvotes = 0, AwardScore = g.Sum(p => (double)p.AwardedScore)
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var reaction in reactions.Where(r => r.Attitude == Shared.Models.PostReactionAttitude.Positive))
|
||||||
|
{
|
||||||
|
if (!postIdToPublisher.TryGetValue(reaction.PostId, out var pubId) ||
|
||||||
|
!publisherStats.TryGetValue(pubId, out var stat)) continue;
|
||||||
|
stat = new { stat.PostCount, Upvotes = stat.Upvotes + 1, stat.Downvotes, stat.AwardScore };
|
||||||
|
publisherStats[pubId] = stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var reaction in reactions.Where(r => r.Attitude == Shared.Models.PostReactionAttitude.Negative))
|
||||||
|
{
|
||||||
|
if (!postIdToPublisher.TryGetValue(reaction.PostId, out var pubId) ||
|
||||||
|
!publisherStats.TryGetValue(pubId, out var stat)) continue;
|
||||||
|
stat = new { stat.PostCount, stat.Upvotes, Downvotes = stat.Downvotes + 1, stat.AwardScore };
|
||||||
|
publisherStats[pubId] = stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
var date = now.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
var publisherIds = publisherStats.Keys.ToList();
|
||||||
|
var publisherMembers = await db.PublisherMembers
|
||||||
|
.Where(m => publisherIds.Contains(m.PublisherId))
|
||||||
|
.ToListAsync();
|
||||||
|
var accountIds = publisherMembers.Select(m => m.AccountId).ToList();
|
||||||
|
var accounts = (await remoteAccounts.GetAccountBatch(accountIds)).ToDictionary(a => Guid.Parse(a.Id), a => a);
|
||||||
|
var publisherAccounts = publisherMembers
|
||||||
|
.GroupBy(m => m.PublisherId)
|
||||||
|
.ToDictionary(g => g.Key, g => g.Select(m => SnAccount.FromProtoValue(accounts[m.AccountId])).ToList());
|
||||||
|
|
||||||
|
// Foreach loop through publishers to calculate experience
|
||||||
|
foreach (var (publisherId, value) in publisherStats)
|
||||||
|
{
|
||||||
|
var postCount = value.PostCount;
|
||||||
|
var upvotes = value.Upvotes;
|
||||||
|
var downvotes = value.Downvotes;
|
||||||
|
var awardScore = value.AwardScore; // Fetch or calculate here
|
||||||
|
|
||||||
|
// Each post counts as 100 experiences,
|
||||||
|
// and each point (upvote - downvote + award score * 0.1) count as 10 experiences
|
||||||
|
var netVotes = upvotes - downvotes;
|
||||||
|
var points = netVotes + awardScore * 0.1;
|
||||||
|
var experienceFromPosts = postCount * 100;
|
||||||
|
var experienceFromPoints = (int)(points * 10);
|
||||||
|
var totalExperience = experienceFromPosts + experienceFromPoints;
|
||||||
|
|
||||||
|
if (!publisherAccounts.TryGetValue(publisherId, out var receivers) || receivers.Count == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Use totalExperience for rewarding
|
||||||
|
foreach (var receiver in receivers)
|
||||||
|
{
|
||||||
|
await experiences.AddRecordAsync(new AddExperienceRecordRequest
|
||||||
|
{
|
||||||
|
Reason = $"Publishing Reward on {date}",
|
||||||
|
ReasonType = "publishers.rewards",
|
||||||
|
AccountId = receiver.Id.ToString(),
|
||||||
|
Delta = totalExperience,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Foreach loop through publishers to set social credit
|
||||||
|
var expiredAt = now.InZone(DateTimeZone.Utc).Date.PlusDays(1).AtStartOfDayInZone(DateTimeZone.Utc).Minus(Duration.FromMilliseconds(1)).ToInstant();
|
||||||
|
foreach (var (publisherId, value) in publisherStats)
|
||||||
|
{
|
||||||
|
var upvotes = value.Upvotes;
|
||||||
|
var downvotes = value.Downvotes;
|
||||||
|
var awardScore = value.AwardScore; // Fetch or calculate here
|
||||||
|
|
||||||
|
var netVotes = upvotes - downvotes;
|
||||||
|
var points = netVotes + awardScore * 0.1;
|
||||||
|
var socialCreditDelta = (int)(points * 10);
|
||||||
|
|
||||||
|
if (socialCreditDelta == 0) continue;
|
||||||
|
|
||||||
|
if (!publisherAccounts.TryGetValue(publisherId, out var receivers) || receivers.Count == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Set social credit for receivers, expired before next settle
|
||||||
|
foreach (var receiver in receivers)
|
||||||
|
{
|
||||||
|
await socialCredits.AddRecordAsync(new AddSocialCreditRecordRequest
|
||||||
|
{
|
||||||
|
Reason = $"Publishing Reward on {date}",
|
||||||
|
ReasonType = "publishers.rewards",
|
||||||
|
AccountId = receiver.Id.ToString(),
|
||||||
|
Delta = socialCreditDelta,
|
||||||
|
ExpiredAt = expiredAt.ToTimestamp(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
DysonNetwork.Sphere/Publisher/PublisherSettlementJob.cs
Normal file
12
DysonNetwork.Sphere/Publisher/PublisherSettlementJob.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Quartz;
|
||||||
|
using DysonNetwork.Sphere.Publisher;
|
||||||
|
|
||||||
|
namespace DysonNetwork.Sphere.Publisher;
|
||||||
|
|
||||||
|
public class PublisherSettlementJob(PublisherService publisherService) : IJob
|
||||||
|
{
|
||||||
|
public async Task Execute(IJobExecutionContext context)
|
||||||
|
{
|
||||||
|
await publisherService.SettlePublisherRewards();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using DysonNetwork.Sphere.Post;
|
using DysonNetwork.Sphere.Post;
|
||||||
|
using DysonNetwork.Sphere.Publisher;
|
||||||
using DysonNetwork.Sphere.WebReader;
|
using DysonNetwork.Sphere.WebReader;
|
||||||
using Quartz;
|
using Quartz;
|
||||||
|
|
||||||
@@ -31,6 +32,13 @@ public static class ScheduledJobsConfiguration
|
|||||||
.WithIdentity("WebFeedScraperTrigger")
|
.WithIdentity("WebFeedScraperTrigger")
|
||||||
.WithCronSchedule("0 0 0 * * ?")
|
.WithCronSchedule("0 0 0 * * ?")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
q.AddJob<PublisherSettlementJob>(opts => opts.WithIdentity("PublisherSettlement"));
|
||||||
|
q.AddTrigger(opts => opts
|
||||||
|
.ForJob("PublisherSettlement")
|
||||||
|
.WithIdentity("PublisherSettlementTrigger")
|
||||||
|
.WithCronSchedule("0 0 0 * * ?")
|
||||||
|
);
|
||||||
});
|
});
|
||||||
services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);
|
services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user