Rework front page to scale much better

Old page took anywhere up to 20s to generate with a 100k builds
collection. This cuts it down to between 1s-2s.
refactor-intermediate-models
Thomas Hounsell 2017-05-17 11:48:39 +01:00
parent b87e303ba9
commit 74e2e0bed8
3 changed files with 113 additions and 66 deletions

View File

@ -153,74 +153,90 @@ namespace BuildFeed.Model
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<FrontPage> SelectFrontPage(ProjectFamily family)
public async Task<Dictionary<ProjectFamily, FrontPage>> SelectFrontPage()
{
FrontPage fp = new FrontPage();
var families = new Dictionary<ProjectFamily, FrontPage>();
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument
{
{"$where", "!this.LabUrl.contains(\"xbox\")"},
IAggregateFluent<BsonDocument> query = _buildCollection.Aggregate()
.Match(new BsonDocument
{
nameof(Build.Family), family
}
}).Sort(sortByCompileDate).Limit(1);
fp.CurrentCanary = await query.FirstOrDefaultAsync();
query = _buildCollection.Find(new BsonDocument
{
{"$where", "!this.LabUrl.contains(\"xbox\")"},
{
nameof(Build.Family), family
},
{
nameof(Build.MajorVersion), 10
},
{
nameof(Build.SourceType), new BsonDocument
{
nameof(Build.Family), new BsonDocument
{
{"$gte", 30}
}
}
})
.Group(new BsonDocument
{
{
"_id", new BsonDocument
{
{nameof(Build.Family), $"${nameof(Build.Family)}"},
{nameof(Build.LabUrl), $"${nameof(Build.LabUrl)}"},
{nameof(Build.SourceType), $"${nameof(Build.SourceType)}"}
}
},
{
"items", new BsonDocument
{
"$in", new BsonArray
{
TypeOfSource.PublicRelease,
TypeOfSource.UpdateGDR
"$push", new BsonDocument
{
{nameof(Build.Id), "$_id"},
{nameof(Build.MajorVersion), $"${nameof(Build.MajorVersion)}"},
{nameof(Build.MinorVersion), $"${nameof(Build.MinorVersion)}"},
{nameof(Build.Number), $"${nameof(Build.Number)}"},
{nameof(Build.Revision), $"${nameof(Build.Revision)}"},
{nameof(Build.Lab), $"${nameof(Build.Lab)}"},
{nameof(Build.BuildTime), $"${nameof(Build.BuildTime)}"}
}
}
}
}
}
}).Sort(sortByCompileDate).Limit(1);
fp.CurrentInsider = await query.FirstOrDefaultAsync();
});
query = _buildCollection.Find(new BsonDocument
var dbResults = await query.ToListAsync();
var results = from g in dbResults
select new
{
Key = new
{
Family = (ProjectFamily)g["_id"].AsBsonDocument[nameof(Build.Family)].AsInt32,
LabUrl = g["_id"].AsBsonDocument[nameof(Build.LabUrl)].AsString,
SourceType = (TypeOfSource)g["_id"].AsBsonDocument[nameof(Build.SourceType)].AsInt32
},
Items = from i in g["items"].AsBsonArray
select new FrontPageBuild
{
Id = i[nameof(Build.Id)].AsGuid,
MajorVersion = (uint)i[nameof(Build.MajorVersion)].AsInt32,
MinorVersion = (uint)i[nameof(Build.MinorVersion)].AsInt32,
Number = (uint)i[nameof(Build.Number)].AsInt32,
Revision = (uint?)i[nameof(Build.Revision)].AsNullableInt32,
Lab = i[nameof(Build.Lab)].AsString,
BuildTime = i[nameof(Build.BuildTime)].ToNullableUniversalTime()
}
};
IEnumerable<ProjectFamily> listOfFamilies = results.GroupBy(g => g.Key.Family).Select(g => g.Key);
foreach (ProjectFamily family in listOfFamilies)
{
{"$where", "((this.MajorVersion === 10 && this.LabUrl.contains(\"_release\")) || this.MajorVersion < 10) && !this.LabUrl.contains(\"xbox\")"},
FrontPage fp = new FrontPage
{
nameof(Build.Family), family
},
{
nameof(Build.SourceType), new BsonDocument
{
{
"$in", new BsonArray
{
TypeOfSource.PublicRelease,
TypeOfSource.UpdateGDR
}
}
}
}
}).Sort(sortByCompileDate).Limit(1);
fp.CurrentRelease = await query.FirstOrDefaultAsync();
CurrentCanary = results.Where(g => g.Key.Family == family && !g.Key.LabUrl.Contains("xbox")).SelectMany(g => g.Items).OrderByDescending(b => b.BuildTime).FirstOrDefault(),
CurrentInsider = results.Where(g => g.Key.Family == family && !g.Key.LabUrl.Contains("xbox") && (g.Key.SourceType == TypeOfSource.PublicRelease || g.Key.SourceType == TypeOfSource.UpdateGDR)).SelectMany(g => g.Items).OrderByDescending(b => b.BuildTime).FirstOrDefault(),
CurrentRelease = results.Where(g => g.Key.Family == family && g.Key.LabUrl.Contains("_release") && !g.Key.LabUrl.Contains("xbox") && (g.Key.SourceType == TypeOfSource.PublicRelease || g.Key.SourceType == TypeOfSource.UpdateGDR)).SelectMany(g => g.Items).OrderByDescending(b => b.BuildTime).FirstOrDefault(),
CurrentXbox = results.Where(g => g.Key.Family == family && g.Key.LabUrl.Contains("xbox")).SelectMany(g => g.Items).OrderByDescending(b => b.BuildTime).FirstOrDefault()
};
query = _buildCollection.Find(new BsonDocument
{
{"$where", "this.LabUrl.contains(\"xbox\")"},
{
nameof(Build.Family), family
}
}).Sort(sortByCompileDate).Limit(1);
fp.CurrentXbox = await query.FirstOrDefaultAsync();
families.Add(family, fp);
}
return fp;
return families;
}
[DataObjectMethod(DataObjectMethodType.Select, false)]

View File

@ -1,10 +1,47 @@
namespace BuildFeed.Model.View
using System;
using System.ComponentModel.DataAnnotations;
using BuildFeed.Local;
using MongoDB.Bson.Serialization.Attributes;
namespace BuildFeed.Model.View
{
public class FrontPage
{
public Build CurrentCanary { get; set; }
public Build CurrentInsider { get; set; }
public Build CurrentRelease { get; set; }
public Build CurrentXbox { get; set; }
public FrontPageBuild CurrentCanary { get; set; }
public FrontPageBuild CurrentInsider { get; set; }
public FrontPageBuild CurrentRelease { get; set; }
public FrontPageBuild CurrentXbox { get; set; }
}
public class FrontPageBuild
{
[Key]
[BsonId]
public Guid Id { get; set; }
[Required]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_MajorVersion))]
public uint MajorVersion { get; set; }
[Required]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_MinorVersion))]
public uint MinorVersion { get; set; }
[Required]
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_BuildNumber))]
public uint Number { get; set; }
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_Revision))]
[DisplayFormat(ConvertEmptyStringToNull = true)]
public uint? Revision { get; set; }
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_LabString))]
public string Lab { get; set; }
[Display(ResourceType = typeof(VariantTerms), Name = nameof(VariantTerms.Model_BuildTime))]
[DisplayFormat(ConvertEmptyStringToNull = true,
ApplyFormatInEditMode = true,
DataFormatString = "{0:yyMMdd-HHmm}")]
public DateTime? BuildTime { get; set; }
}
}

View File

@ -38,13 +38,7 @@ namespace BuildFeed.Controllers
#endif
public async Task<ActionResult> Index()
{
var items = new Dictionary<ProjectFamily, FrontPage>
{
{ProjectFamily.Redstone3, await _bModel.SelectFrontPage(ProjectFamily.Redstone3)},
{ProjectFamily.Feature2, await _bModel.SelectFrontPage(ProjectFamily.Feature2)},
{ProjectFamily.Redstone2, await _bModel.SelectFrontPage(ProjectFamily.Redstone2)},
{ProjectFamily.Redstone, await _bModel.SelectFrontPage(ProjectFamily.Redstone)}
};
Dictionary<ProjectFamily, FrontPage> items = await _bModel.SelectFrontPage();
return View(nameof(Index), items);
}