{"id":17061355,"url":"https://github.com/filipw/async-expiring-lazy","last_synced_at":"2025-04-12T18:14:04.176Z","repository":{"id":48237836,"uuid":"72540309","full_name":"filipw/async-expiring-lazy","owner":"filipw","description":"AsyncExpiringLazy","archived":false,"fork":false,"pushed_at":"2025-02-05T15:31:32.000Z","size":64,"stargazers_count":37,"open_issues_count":0,"forks_count":7,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-12T18:13:55.278Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/filipw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-11-01T13:46:25.000Z","updated_at":"2025-02-05T15:21:08.000Z","dependencies_parsed_at":"2024-11-07T15:03:21.193Z","dependency_job_id":"74b0b59f-3841-45e3-832e-b7a13d41040c","html_url":"https://github.com/filipw/async-expiring-lazy","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filipw%2Fasync-expiring-lazy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filipw%2Fasync-expiring-lazy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filipw%2Fasync-expiring-lazy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/filipw%2Fasync-expiring-lazy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/filipw","download_url":"https://codeload.github.com/filipw/async-expiring-lazy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248610336,"owners_count":21132920,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-14T10:46:52.778Z","updated_at":"2025-04-12T18:14:04.149Z","avatar_url":"https://github.com/filipw.png","language":"C#","funding_links":[],"categories":["others"],"sub_categories":[],"readme":"# Async Expiring Lazy\r\n\r\n\r\nSee [blog article](https://www.strathweb.com/2016/11/lazy-async-initialization-for-expiring-objects/) for more background details and a [follow up post](https://www.strathweb.com/2021/07/eager-refresh-of-values-for-asyncexpiringlazy/) for further update.\r\n\r\n## Installation\r\n\r\nGrab the Nuget package called [Strathweb.AsyncExpiringLazy](https://www.nuget.org/packages/Strathweb.AsyncExpiringLazy/). It is cross compiled for .NET Standard 1.1, .NET Standard 2.0 and .NET Framework 4.6.1 and compatible with:\r\n\r\n - .NET Framework 4.6.1\r\n - all version of .NET Core\r\n - Xamarin\r\n - Mono\r\n - Universal Windows Platform\r\n \r\nLatest version: [![Nuget](http://img.shields.io/nuget/v/Strathweb.AsyncExpiringLazy.svg?maxAge=10800)](https://www.nuget.org/packages/Strathweb.AsyncExpiringLazy/)\r\n\r\n## Usage\r\n\r\nThe code sample shows creating a lazy epxiring value with `AsyncExpiringLazy\u003cT\u003e` and letting it get recreated on first reuse after expiration.\r\n\r\n```csharp\r\nvar testInstance = new AsyncExpiringLazy\u003cTokenResponse\u003e(async (metadata, ct) =\u003e\r\n{\r\n    await Task.Delay(1000, ct);\r\n    return new ExpirationMetadata\u003cTokenResponse\u003e\r\n    {\r\n        Result = new TokenResponse\r\n        {\r\n            AccessToken = Guid.NewGuid().ToString()\r\n        }, ValidUntil = DateTimeOffset.UtcNow.AddSeconds(2)\r\n    };\r\n});\r\n\r\n// 1. check if value is created - shouldn't\r\nAssert.False(await testInstance.IsValueCreated());\r\n\r\n// 2. fetch lazy expiring value\r\nvar token = await testInstance.Value();\r\n\r\n// 3a. verify it is created now\r\nAssert.True(await testInstance.IsValueCreated());\r\n\r\n// 3b. verify it is not null\r\nAssert.NotNull(token.AccessToken);\r\n\r\n// 4. fetch the value again. Since it's lifetime is 2 seconds, it should be still the same\r\nvar token2 = await testInstance.Value();\r\nAssert.Same(token, token2);\r\n\r\n// 5. sleep for 2 seconds to let the value expire\r\nawait Task.Delay(2000);\r\n\r\n// 6a. verify the value expired\r\nAssert.False(await testInstance.IsValueCreated());\r\n\r\n// 6b. fetch again\r\nvar token3 = await testInstance.Value();\r\n\r\n// 7. verify we now have a new (recreated) value - as the previous one expired\r\nAssert.NotSame(token2, token3);\r\n\r\n// 8. invalidate the value manually before it has a chance to expire\r\nawait testInstance.Invalidate();\r\n\r\n// 9. check if value is created - shouldn't anymore\r\nAssert.False(await testInstance.IsValueCreated());\r\n```\r\n\r\nThe next code sample shows creating a lazy epxiring value with `AsyncExpiringEager\u003cT\u003e` and letting it get recreated silently as soon as it expires.\r\nPay attetion to the different from the previous example at step `6a`.\r\n\r\n```csharp\r\nusing var testInstance = new AsyncExpiringEager\u003cTokenResponse\u003e(async (metadata, ct) =\u003e\r\n{\r\n    await Task.Delay(1000, ct);\r\n    return new ExpirationMetadata\u003cTokenResponse\u003e\r\n    {\r\n        Result = new TokenResponse\r\n        {\r\n            AccessToken = Guid.NewGuid().ToString()\r\n        }, ValidUntil = DateTimeOffset.UtcNow.AddSeconds(2)\r\n    };\r\n});\r\n\r\n// 1. check if value is created - shouldn't\r\nAssert.False(testInstance.IsValueCreated());\r\n\r\n// 2. fetch lazy expiring value\r\nvar token = await testInstance.Value();\r\n\r\n// 3a. verify it is created now\r\nAssert.True(testInstance.IsValueCreated());\r\n\r\n// 3b. verify it is not null\r\nAssert.NotNull(token.AccessToken);\r\n\r\n// 4. fetch the value again. Since it's lifetime is 2 seconds, it should be still the same\r\nvar token2 = await testInstance.Value();\r\nAssert.Same(token, token2);\r\n\r\n// 5. sleep for 2 seconds to let the value expire\r\nawait Task.Delay(2000);\r\n\r\n// 6a. verify the value was eagerly created just before it expired\r\nAssert.True(testInstance.IsValueCreated());\r\n\r\n// 6b. fetch again\r\nvar token3 = await testInstance.Value();\r\n\r\n// 7. verify we now have a new (recreated) value - as the previous one expired\r\nAssert.NotSame(token2, token3);\r\n\r\n// 8. invalidate the value manually before it has a chance to expire\r\ntestInstance.Invalidate();\r\n\r\n// 9. check if value is created - shouldn't anymore\r\nAssert.False(testInstance.IsValueCreated());\r\n```\r\n\r\n## License\r\n\r\n[MIT](https://github.com/filipw/async-expiring-lazy/blob/master/LICENSE)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffilipw%2Fasync-expiring-lazy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffilipw%2Fasync-expiring-lazy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffilipw%2Fasync-expiring-lazy/lists"}