erikbra / grate

grate - the SQL scripts migration runner
MIT License
209 stars 40 forks source link

Doesn't work on console app NET 8 using grate.sqlserver #549

Closed Edgaras91 closed 4 months ago

Edgaras91 commented 4 months ago

Describe the bug When executing await GrateMigrator.Migrate(); using sqlserver package the console logs outputs the process 5 times (multiple times) instead of one, with the wrong db script path of C:\Users[user]\AppData\Local\Temp\tmpaia1mc.tmp\up instead of "up" near local

To Reproduce Create a console app NET 8 with grate.sqlserver nuget package and the following code in program.cs:

var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging(x => x.AddSimpleConsole(y => y.SingleLine = true));
serviceCollection.AddGrate(builder =>
    {
        builder
            .WithSqlFilesDirectory("/db")
            .WithConnectionString("Server=localhost;Database=Database;Trusted_Connection=True; Encrypt=false");
    })
    .UseSqlServer(); // Important!, you need to specify the database type to use.
var serviceProvider = serviceCollection.BuildServiceProvider();
var grateMigrator = serviceProvider.GetRequiredService<IGrateMigrator>();
await grateMigrator.Migrate();

Expected behavior Single execution, with paths to db folder next to .exe (bin folder in debug)

Desktop (please complete the following information):

Additional context Was this ever tested on console app? That's how we used to use RoundhousE. Maybe create automated tests?

The issue itself I think is related to threading, because when debugging, the pointer jumps around a lot, re entering "Migration" code multiple times. Also, the path of local\temp may be where the exe is being executed, also I suspect is what "Directory.GetCurrentDirectory()" is retrieving when handing over to background threads (async)

I tried running in async main: static async Task Main(string[] args)

Edgaras91 commented 4 months ago

I was missing an absolute (not relative) path (it was unclear what path it wanted). Below made "progress" for me: $"{Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location)}/db/Accounts" Additionally, this grate.sqlserver runs "migrations" 4 times in above mentioned temp folders before it finally runs my scripts

erikbra commented 2 months ago

Hi, @Edgaras91 - what you are seeing, are the internal grate migrations. I have an internal grate folder structure (since 1.7.0) that handles migrations of the grate tables themselves. Because grate is the best way to handle DB migrations, right?

TLDR:

If you add a log filter on the category "Grate.Migration.Internal" with the minimum log level set to very high, you won't see any of these logs (unless something critical happens)

services.AddLogging().AddFilter("Grate.Migration.Internal", LogLevel.Critical)

e.g:

services.AddLogging(logging => logging.AddConsole(options =>
    {
        options.FormatterName = GrateConsoleFormatter.FormatterName;
        options.LogToStandardErrorThreshold = LogLevel.Warning;
    })
    .AddFilter("Grate.Migration.Internal", LogLevel.Critical)
    .SetMinimumLevel(config.Verbosity)
    .AddConsoleFormatter<GrateConsoleFormatter, SimpleConsoleFormatterOptions>());

like it is done here:

https://github.com/erikbra/grate/commit/13132276d62123b21946b436d81bc63d1b6b7ee5#diff-d56f75d76cfd65a248e21207dcd60f73325afb6e532d4185639b3fa65eee38bcR128

(details below)

This is a kind of recursive (Inception?) use of grate, and is an internal grate topic. I use temporary folders to store the grate scripts, and run them off there. This is why you see unexpected folders in the migration history (script output).

On the command-line tool grate, I have set verbosity of logging to very low on the internal migrations, to avoid having the users of the tool notice these internal migrations. However, when running grate programmatically, you won't get this "for free".

You can see in this commit, that I set the LogCategory of the internal migrations specifically:

https://github.com/erikbra/grate/commit/13132276d62123b21946b436d81bc63d1b6b7ee5#diff-5bdc6858a67fb69b6be8d2f23bc3792366367c720b71ffa66230b2bbae9d308cR18

And, as you see, there are two different log levels for the "Internal" and the "InternalBootstrap":

https://github.com/erikbra/grate/commit/13132276d62123b21946b436d81bc63d1b6b7ee5#diff-5bdc6858a67fb69b6be8d2f23bc3792366367c720b71ffa66230b2bbae9d308cR18