Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Distribute cron tasks #3326

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
fe0c327
Acquire a lease per cron task
tgregory-block Jun 18, 2024
2a41ba9
Add backwards compatibility and update README
din-cashapp Jun 19, 2024
4b0b4f9
resolve comments
din-cashapp Jun 24, 2024
7aa7afe
API dump
tgregory-block Jun 24, 2024
7b7a0a6
fixes
din-cashapp Jun 25, 2024
cdf5d07
Remove unnecessary class name sanitization
tgregory-block Jun 25, 2024
4c8d547
Lease held elsewhere WIP
tgregory-block Aug 20, 2024
7c32ffd
Implement TestFixture for log collectors
mmollaverdi Aug 5, 2024
8f5b240
Implement TestFixture for metrics
mmollaverdi Aug 5, 2024
7c600c8
Implement TestFixture for JdbcTestingModule
mmollaverdi Aug 6, 2024
93c6b21
Support more source formats and Guice explorer
damar-block Aug 6, 2024
3cdb3e4
Updates the hashing algorithm used in the `ClusterHashRing`
salamagd Aug 6, 2024
f95301e
Implement TestFixture for dynamodb
mmollaverdi Aug 7, 2024
f49a286
Expose service graph in admin console using d3 graph template
katukota Aug 7, 2024
30a98f9
Fix InProcessDynamoDbTests for Apple Silicon
tyiu Aug 7, 2024
3003e10
Update misk.feature.Attributes to have a `with` method that
ean5533 Aug 8, 2024
2bdbd1a
Defer the shutdown of JettyService until after Guava managed
kevink-sq Aug 8, 2024
c8bafb6
feat: Add new param to Redis modules for specific config
rainecp Aug 9, 2024
0b6ac89
The original implementation of `TaggedLogger` became heavy, stateful and
afkelsall Aug 11, 2024
6b15723
In this approach, we rebuild the url with path and parse it so that
lakpic Aug 12, 2024
988a576
Skip resetting DB if DataSourceService has not started
mmollaverdi Aug 13, 2024
2dd10bb
Update MiskTestExtension to stop Jetty in the shutdown hook
kevink-sq Aug 13, 2024
c10e0fe
Injector reuse - support test modules with constructor
mmollaverdi Aug 14, 2024
9cd88a9
We are not using DefaultBindingScopingVisitor's visitOther
damar-block Aug 14, 2024
75ef2b0
Fixes some misk test reuse injector bugs
mmollaverdi Aug 15, 2024
7adc972
Add Mutable AI badge to Misk readme
damar-block Aug 15, 2024
9ac94ab
[Misk Test Flakes] misk.jdbc.CockroachDbRealTransacterTest
katukota Aug 15, 2024
a722cfb
Only run buildMiskWeb on shadowJar
yissachar Aug 16, 2024
7744ee3
Misk test injector reuse - dynamodb reset fix and mockito test
mmollaverdi Aug 17, 2024
d705db1
Build misk-web on assemble, not just shadowJar
yissachar Aug 19, 2024
2d2ec8b
Revert only building misk-web on assemble
yissachar Aug 19, 2024
99f639a
Fix flaky test
katukota Aug 19, 2024
6d42628
Add flush_interval to the LaunchDarklyConfig, default to the
meghans-cash Aug 20, 2024
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<img src="https://github.com/cashapp/misk/raw/master/misk.png" width="300">

[<img src="https://img.shields.io/maven-central/v/com.squareup.misk/misk.svg?label=latest%20release"/>](http://search.maven.org/#search%7Cga%7C1%7Ccom.squareup.misk)
[<img src="https://img.shields.io/maven-central/v/com.squareup.misk/misk.svg?label=latest%20release"/>](http://search.maven.org/#search%7Cga%7C1%7Ccom.squareup.misk) [![Mutable.ai Auto Wiki](https://img.shields.io/badge/Auto_Wiki-Mutable.ai-blue)](https://wiki.mutable.ai/cashapp/misk)

* Releases
* See most recent [public build][snap]
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ tempest2Testing = { module = "app.cash.tempest:tempest2-testing" }
tempest2TestingDocker = { module = "app.cash.tempest:tempest2-testing-docker" }
tempest2TestingInternal = { module = "app.cash.tempest:tempest2-testing-internal" }
tempest2TestingJvm = { module = "app.cash.tempest:tempest2-testing-jvm" }
tempestBom = { module = "app.cash.tempest:tempest-bom", version = "2024.03.25.180845-91fd675" }
tempestBom = { module = "app.cash.tempest:tempest-bom", version = "2024.08.07.002316-64f40ef" }
tempestTesting = { module = "app.cash.tempest:tempest-testing" }
tempestTestingDocker = { module = "app.cash.tempest:tempest-testing-docker" }
tempestTestingInternal = { module = "app.cash.tempest:tempest-testing-internal" }
Expand Down
26 changes: 21 additions & 5 deletions misk-admin/api/misk-admin.api
Original file line number Diff line number Diff line change
Expand Up @@ -931,17 +931,19 @@ public class misk/web/metadata/guice/GitHubSourceUrlProvider : misk/web/metadata
}

protected final class misk/web/metadata/guice/GitHubSourceUrlProvider$SourceLocation {
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Ljava/lang/String;
public final fun component3 ()Ljava/lang/String;
public final fun component4 ()I
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Lmisk/web/metadata/guice/GitHubSourceUrlProvider$SourceLocation;
public static synthetic fun copy$default (Lmisk/web/metadata/guice/GitHubSourceUrlProvider$SourceLocation;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IILjava/lang/Object;)Lmisk/web/metadata/guice/GitHubSourceUrlProvider$SourceLocation;
public final fun component4 ()Ljava/lang/String;
public final fun component5 ()Ljava/lang/Integer;
public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;)Lmisk/web/metadata/guice/GitHubSourceUrlProvider$SourceLocation;
public static synthetic fun copy$default (Lmisk/web/metadata/guice/GitHubSourceUrlProvider$SourceLocation;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;ILjava/lang/Object;)Lmisk/web/metadata/guice/GitHubSourceUrlProvider$SourceLocation;
public fun equals (Ljava/lang/Object;)Z
public final fun getClassName ()Ljava/lang/String;
public final fun getFunctionName ()Ljava/lang/String;
public final fun getLineNumber ()I
public final fun getInnerClassName ()Ljava/lang/String;
public final fun getLineNumber ()Ljava/lang/Integer;
public final fun getPackageName ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
Expand All @@ -965,6 +967,20 @@ public final class misk/web/metadata/guice/GuiceTabIndexAction : misk/web/action
public final class misk/web/metadata/guice/GuiceTabIndexAction$Companion {
}

public final class misk/web/metadata/servicegraph/ServiceGraphDashboardTabModule : misk/inject/KAbstractModule {
public fun <init> ()V
}

public final class misk/web/metadata/servicegraph/ServiceGraphTabIndexAction : misk/web/actions/WebAction {
public static final field Companion Lmisk/web/metadata/servicegraph/ServiceGraphTabIndexAction$Companion;
public static final field PATH Ljava/lang/String;
public fun <init> (Lmisk/web/v2/DashboardPageLayout;Lcom/google/inject/Provider;)V
public final fun get ()Ljava/lang/String;
}

public final class misk/web/metadata/servicegraph/ServiceGraphTabIndexAction$Companion {
}

public final class misk/web/metadata/webaction/WebActionsDashboardTabModule : misk/inject/KAbstractModule {
public fun <init> (Z)V
}
Expand Down
1 change: 1 addition & 0 deletions misk-admin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies {
api(project(":misk-actions"))
api(project(":misk-config"))
api(project(":misk-inject"))
api(project(":misk-service"))
api(libs.kotlinxHtml)
implementation(libs.kotlinLogging)
implementation(libs.moshiCore)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import misk.web.metadata.config.ConfigDashboardTabModule
import misk.web.metadata.config.ConfigMetadataAction
import misk.web.metadata.database.DatabaseDashboardTabModule
import misk.web.metadata.guice.GuiceDashboardTabModule
import misk.web.metadata.servicegraph.ServiceGraphDashboardTabModule
import misk.web.metadata.webaction.WebActionsDashboardTabModule
import misk.web.v2.NavbarModule

Expand Down Expand Up @@ -35,6 +36,7 @@ class AdminDashboardModule @JvmOverloads constructor(
install(ConfigDashboardTabModule(isDevelopment, configTabMode))
install(DatabaseDashboardTabModule(isDevelopment))
install(GuiceDashboardTabModule())
install(ServiceGraphDashboardTabModule())
install(WebActionsDashboardTabModule(isDevelopment))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,32 @@ import java.net.URLEncoder
*/

open class GitHubSourceUrlProvider @Inject constructor() : GuiceSourceUrlProvider {
private val sourceWithLineNumberRegex = """^([\w.]+)\.((?:\w+\$?)+)\.(\w+)\(.*:(\d+)\)$""".toRegex()
private val sourceWithLineNumberRegex = Regex("""^([\w.]+)\.((?:\w+\$?)+)\.(\w+)\(.*:(\d+)\)$""")
private val classRegex = Regex("""class\s+([a-zA-Z0-9_.$]+)""")
private val functionRegex = Regex("""(?:\w+\s+)?(?:\w+\s+)?(?:\w+\s+)?([a-zA-Z0-9_.$]+)\.([a-zA-Z0-9_.$]+)\(([^)]*)\)""")
protected data class SourceLocation(
val packageName: String,
val className: String,
val functionName: String,
val lineNumber: Int,
val innerClassName: String?,
val functionName: String?,
val lineNumber: Int?,
)
override fun urlForSource(source: String): String? {
val sourceLocation = maybeSourceLocation(source) ?: return null
return githubSearchUrl(sourceLocation)
}

protected open fun generateQuery(source: SourceLocation): String {
return """"package ${source.packageName}" ${source.className.replace('$', ' ')} ${source.functionName}"""
val sb = StringBuilder()
sb.append(""""package ${source.packageName}"""")
sb.append(" ${source.className}")
if (source.innerClassName != null) {
sb.append(" ${source.innerClassName}")
}
if (source.functionName != null) {
sb.append(" ${source.functionName}")
}
return sb.toString()
}

private fun githubSearchUrl(source: SourceLocation): String {
Expand All @@ -30,15 +42,54 @@ open class GitHubSourceUrlProvider @Inject constructor() : GuiceSourceUrlProvide
}

private fun maybeSourceLocation(source: String): SourceLocation? {
val matchResult = sourceWithLineNumberRegex.matchEntire(source)

return if (matchResult != null) {
// Extract the package, class, function names, and line number from the match groups
sourceWithLineNumberRegex.matchEntire(source)?.let {matchResult ->
val (packageName, className, functionName, lineNumberStr) = matchResult.destructured
val (innerClassName, outerClassName) = parseClass(className)
val lineNumber = lineNumberStr.toInt()
SourceLocation(packageName, className, functionName, lineNumber)
} else {
null
return SourceLocation(
packageName = packageName,
className = outerClassName,
innerClassName = innerClassName,
functionName = functionName,
lineNumber = lineNumber
)
}

classRegex.find(source)?.let { matchResult ->
val fullClassName = matchResult.groupValues[1]
val packageName = fullClassName.substringBeforeLast('.')
val className = fullClassName.substringAfterLast('.')
val (innerClassName, outerClassName) = parseClass(className)
return SourceLocation(
packageName = packageName,
className = outerClassName,
innerClassName = innerClassName,
functionName = null,
lineNumber = null
)
}

functionRegex.find(source)?.let {matchResult ->
val fullClassName = matchResult.groupValues[1]
val functionName = matchResult.groupValues[2].substringBefore('$')
val packageName = fullClassName.substringBeforeLast('.')
val className = fullClassName.substringAfterLast('.')
val (innerClassName, outerClassName) = parseClass(className)
return SourceLocation(
packageName = packageName,
className = outerClassName,
innerClassName = innerClassName,
functionName = functionName,
lineNumber = null
)
}

return null
}

private fun parseClass(className: String): Pair<String?, String> {
val innerClassName = if ('$' in className) className.substringAfter('$') else null
val outerClassName = if ('$' in className) className.substringBefore('$') else className
return Pair(innerClassName, outerClassName)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package misk.web.metadata.servicegraph

import misk.inject.KAbstractModule
import misk.web.WebActionModule
import misk.web.dashboard.AdminDashboard
import misk.web.dashboard.AdminDashboardAccess
import misk.web.dashboard.DashboardModule

class ServiceGraphDashboardTabModule: KAbstractModule() {
override fun configure() {
install(WebActionModule.create<ServiceGraphTabIndexAction>())
install(DashboardModule.createHotwireTab<AdminDashboard, AdminDashboardAccess>(
slug = "service-graph",
urlPathPrefix = ServiceGraphTabIndexAction.PATH,
menuCategory = "Container Admin",
menuLabel = "Service Graph",
))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package misk.web.metadata.servicegraph

import com.google.inject.Provider
import jakarta.inject.Inject
import jakarta.inject.Singleton
import kotlinx.html.div
import kotlinx.html.h1
import kotlinx.html.script
import kotlinx.html.unsafe
import misk.metadata.servicegraph.ServiceGraphMetadata
import misk.web.Get
import misk.web.ResponseContentType
import misk.web.actions.WebAction
import misk.web.dashboard.AdminDashboardAccess
import misk.web.mediatype.MediaTypes
import misk.web.metadata.toFormattedJson
import misk.web.v2.DashboardPageLayout
import wisp.moshi.adapter
import wisp.moshi.defaultKotlinMoshi

@Singleton
class ServiceGraphTabIndexAction @Inject constructor(
private val dashboardPageLayout: DashboardPageLayout,
private val serviceGraphMetadataProvider: Provider<ServiceGraphMetadata>,
) : WebAction {
@Get(PATH)
@ResponseContentType(MediaTypes.TEXT_HTML)
@AdminDashboardAccess
fun get(): String = dashboardPageLayout
.newBuilder()
.headBlock {
script {
src = "https://cdn.jsdelivr.net/npm/d3@7"
type = "text/javascript"
}
}
.build { _, _, _ ->
val metadataArray = defaultKotlinMoshi
.adapter<List<ServiceGraphMetadata.GraphPairs>>()
.toFormattedJson(serviceGraphMetadataProvider.get().graphVisual)

div("p-4 sm:p-6 lg:p-8") {

h1("text-3xl font-medium mb-8") {
+"""Service Graph"""
}

div("svg-container") { }

// JavaScript code in a block
script {
unsafe {
+"""
var metadata = $metadataArray;

var linkColor = "steelblue" // Define a single color for all links

drag = simulation => {

function dragstarted(event, d) {
if (!event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}

function dragged(event, d) {
d.fx = event.x;
d.fy = event.y;
}

function dragended(event, d) {
if (!event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}

return d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
}

function linkArc(d) {
const r = Math.hypot(d.target.x - d.source.x, d.target.y - d.source.y);
return "M" + d.source.x + "," + d.source.y + "A" + r + "," + r + " 0 0,1 " + d.target.x + "," + d.target.y;
}

var width = 1600;
var height = 1000;
var margin = 500;
var nodes = Array.from(new Set(metadata.flatMap(l => [l.source, l.target])), id => ({id}));
var links = metadata.map(d => Object.create(d))

// Set initial positions for the nodes
nodes.forEach(node => {
node.x = Math.random() * width + margin;
node.y = Math.random() * height + margin;
});

var simulation = d3.forceSimulation(nodes)
.force("link", d3.forceLink(links).id(d => d.id).distance(200))
.force("charge", d3.forceManyBody().strength(-2000))
.force("x", d3.forceX().strength(0.1))
.force("y", d3.forceY().strength(0.1));

var svg = d3.select(".svg-container").append("svg")
.attr("viewBox", [-margin, -margin, width, height])
.attr("width", "100%")
.attr("height", "100%")
.attr("style", "max-width: 100%; height: auto; font: 18px sans-serif;");

// Defines arrows on the links
svg.append("defs").selectAll("marker")
.data(["link"])
.join("marker")
.attr("id", d => "arrow-" + d)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", -0.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("path")
.attr("fill", linkColor)
.attr("d", "M0,-5L10,0L0,5");

// Defines links between nodes
var link = svg.append("g")
.attr("fill", "none")
.attr("stroke-width", 2.5)
.selectAll("path")
.data(links)
.join("path")
.attr("stroke", linkColor)
.attr("marker-end", d => "url(#arrow-link)");

// Defines actual nodes
var node = svg.append("g")
.attr("fill", "currentColor")
.attr("stroke-linecap", "round")
.attr("stroke-linejoin", "round")
.selectAll("g")
.data(nodes)
.join("g")
.call(drag(simulation));

node.append("circle")
.attr("stroke", "white")
.attr("stroke-width", 1.5)
.attr("r", 4);

node.append("text")
.attr("x", 12)
.attr("y", "0.31em")
.text(d => d.id)
.clone(true).lower()
.attr("fill", "none")
.attr("stroke", "white")
.attr("stroke-width", 3);

simulation.on("tick", () => {
link.attr("d", linkArc);
node.attr("transform", d => "translate(" + d.x + "," + d.y + ")");
});

Object.assign(svg.node(), {scales: {linkColor}});
""".trimIndent()
}
}
}
}

companion object {
const val PATH = "/_admin/service-graph/"
}
}
Loading
Loading