Skip to content

Add spawnProcessDetached#5483

Merged
wilzbach merged 9 commits intodlang:masterfrom
FreeSlave:spawnProcessDetached
Jul 25, 2017
Merged

Add spawnProcessDetached#5483
wilzbach merged 9 commits intodlang:masterfrom
FreeSlave:spawnProcessDetached

Conversation

@FreeSlave
Copy link
Contributor

@FreeSlave FreeSlave commented Jun 14, 2017

spawnProcessDetached is function similar to spawnProcess, but user does not need to wait on spawned process to avoid zombies (resource leak). Instead of returning Pid instance spawnProcessDetached returns integer pid via pointer. Rationale: user should not be able to wait on detached process.

Currently only Posix version is implemented. It uses double fork technique and setsid to detach the new process from its caller. Since this implementation reuses a lot of stuff from spawnProcess I moved some implementation details to separate private functions to share them between spawnProcess and spawnProcessDetached.

THIS IS WIP
I'll add more unittests and Windows version later. For now say if you like the idea.

@CyberShadow
Copy link
Member

CyberShadow commented Jun 14, 2017

I believe that on Windows, you simply have to close the process handle as soon as the process is created to effectively "detach" the process. (This is not the same as a detached console window.)

Can this be implemented as a Config flag instead? I'm not sure about adding an entire overload set. Then it can be used for spawnShell as well. Pid will likely need a few changes to make waiting on a detached processes an explicit error.

@FreeSlave
Copy link
Contributor Author

I believe that on Windows, you simply have to close the process handle as soon as the process is created to effectively "detach" the process.

I believe so. This is another reason why I did not want to use Pid class. Process handle is part of Pid class on Windows. Closing it will make osHandle be able to be null. So users will need to check for osHandle not being null if they want to use it. That differs from the current situation when osHandle is always not null. And it's also inconsistent with Posix, where osHandle is same as pid and therefore always valid. Do you think it is ok?

@CyberShadow
Copy link
Member

So users will need to check for osHandle not being null if they want to use it.

I think it's more of not doing a thing that doesn't make sense to do.

And it's also inconsistent with Posix, where osHandle is same as pid and therefore always valid.

If you spawn a detached process, technically there is no guarantee that the PID remains valid for any amount of time - the process may exit on its own and the OS may assign the PID to another process. So, if we are to reuse Pid, probably the best course is a private bool owned field (which is false for detached processes), and kill and wait require that owned is true.

CC @schveiguy @kyllingstad

@FreeSlave
Copy link
Contributor Author

FreeSlave commented Jun 14, 2017

kill and wait require that owned is true

Why would kill require owned is true? You can kill any process via task manager or "kill" program which are clearly do not own this process.

@CyberShadow
Copy link
Member

Because it might not be the process you actually intend to kill - that process may have exited a long time ago.

@FreeSlave
Copy link
Contributor Author

Got it.
I'm still not sure that Pid class can be re-used here. There was that PR #5086 that introduced possibility to have non-owned Pid instances. And it was reverted later. Probably because it complicates the usage of other functions (like already said wait and kill).

@CyberShadow
Copy link
Member

#5086 had more problems than that, though (killing processes being an intrinsically platform-dependent operation; needing to call OpenProcess on Windows). I think overloading Pid here makes more sense than adding an overload set.

@kyllingstad
Copy link
Contributor

I think overloading Pid here makes more sense than adding an overload set.

I very much agree with this.

@FreeSlave
Copy link
Contributor Author

FreeSlave commented Jun 15, 2017

Added Pid.owned property and Config.detached constant.
Also added separate unittest to check non-ability of waiting/killing not owned process. It runs OK, but I get this message at terminal

/bin/sh: 0: Can't open /tmp/std.process temporary file 76b5fac2-57f8-4f5b-88dc-9fd27c32ae73

Copy link
Member

@CyberShadow CyberShadow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would like to review the implementation after the refactorings are undone.

std/process.d Outdated
version(Posix)
{
private:
const(char)[] getExecutablePath(const(char)[] name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there is no longer an overload set, these refactorings aren't needed any more, right? If so, can they be undone?


/**
Spawn process in detached state. This removes the need in calling
$(LREF wait) to clean up the process resources.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should have a note here that calling wait or kill with the resulting Pid is invalid.

std/process.d Outdated
This is $(D true) if process was spawned without $(LREF Config.detached), $(D false)
otherwise. You can't $(LREF wait) for or $(LREF kill) process you don't own.
*/
@property bool owned() const @safe pure nothrow
Copy link
Member

@CyberShadow CyberShadow Jun 15, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to make this public. I can't think of many cases that programs would mix owned and non-owned Pids and require distinguishing them. Making it an implementation detail also allows changing the underlying implementation in the future, if necessary.

std/process.d Outdated
int performWait(bool block) @trusted
{
import std.exception : enforceEx;
enforceEx!ProcessException(_owned, "Attempt to wait for the not owned process");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider "Can't wait on a detached process"

std/process.d Outdated
int performWait(bool block) @trusted
{
import std.exception : enforceEx;
enforceEx!ProcessException(_owned, "Attempt to wait for the not owned process");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

std/process.d Outdated

Throws:
$(LREF ProcessException) on failure.
$(LREF ProcessException) on failure or on attempt to wait for not owned process.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider "detached" or "non-child" instead of "not owned", the "owned" term should be an implementation detail

std/process.d Outdated

Throws:
$(LREF ProcessException) on failure.
$(LREF ProcessException) on failure or on attempt to wait for not owned process.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

std/process.d Outdated

Throws:
$(LREF ProcessException) on error (e.g. if codeOrSignal is invalid).
or on attempt to kill not owned process.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

std/process.d Outdated
void kill(Pid pid, int codeOrSignal)
{
import std.exception : enforceEx;
enforceEx!ProcessException(pid.owned(), "Attempt to kill not owned process");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

@CyberShadow
Copy link
Member

It runs OK, but I get this message at terminal

Is this an expected and unavoidable effect of the unit test, or do you need time/assistance in tracking it down?

@FreeSlave
Copy link
Contributor Author

Is this an expected and unavoidable effect of the unit test, or do you need time/assistance in tracking it down?

It should not happen. It's simple TestScript usage. But I can't understand why it happens.

@FreeSlave
Copy link
Contributor Author

FreeSlave commented Jun 15, 2017

Ok, I think I got it. TestScript destructor runs (effectively removing the file) before file execution. Looks like race condition between /bin/sh running with script file and removing this file by unittest.
We can overcome this by adding Thread.sleep. What do you think?

@FreeSlave FreeSlave force-pushed the spawnProcessDetached branch 2 times, most recently from 45c0286 to 827dcd5 Compare June 16, 2017 00:19
else
throw ProcessException.newFromErrno("Could not create pipe to get process pid");
}
scope(exit) if (config & Config.detached) close(pidPipe[0]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to not reuse the same pipe used for communicating the result (forkPipe)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After the second fork started the first and the second forks run in parallel. I can't ensure that pid will be written to the pipe before possible errors.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Please add this explanation as a comment somewhere.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess calling getpid from the second child is also a possibility, but I guess it's not worth the change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's also a possibility that the second fork fails. In this case we would need to pass fictitious pid from the first fork to adjust.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make these considerations a nice comment

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already considered in the comment before int[2] pidPipe;

close(workDirFD);
}
close(workDirFD);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why change the working directory in the second fork? Wouldn't it be simpler to change it in the first fork regardless of Config.detached?

std/process.d Outdated
pfds[i].fd = i + 3;
pfds[i].events = 0;
pfds[i].revents = 0;
setsid();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, isn't setsid supposed to be called from the first fork (so that the session leader is killed)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. Will change.

Copy link
Contributor Author

@FreeSlave FreeSlave Jun 18, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found that setsid makes some apps run incorrectly when starting from terminal without setting stdin to /dev/null.
E.g. run setsid openarena from terminal. It shows a window, but does render anything.
Should we do anything about that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately I am not sufficiently familiar with the subject to confidently answer that.

From looking online, I noticed that setsid is something that is often done when double-forking, but not prescriptively so. Perhaps it only makes sense for non-interactive daemon processes?

Copy link
Contributor Author

@FreeSlave FreeSlave Jun 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't setsid, the spawned process will belong to the same session so pkill -s '$sid' will send signal to this process too.
However on my system all my desktop applications belong to the same session, so it's ok.
We can add another flag to config to control whether the forked child should call setsid.

Copy link
Member

@CyberShadow CyberShadow Jun 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so correct me if I'm wrong, but as I understand the most commonly-observed difference will be that ^C will not kill the spawned process if it's in the same session.

In which case, it does sound like it's worthy of a Flag addition, with the Windows implementation being mapped to the CREATE_NEW_PROCESS_GROUP process creation flag.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be worth leaving it for a separate PR.

Copy link
Contributor Author

@FreeSlave FreeSlave Jun 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^C is sent only to the foreground processes of session. And session has distinction between foreground and background processes only if it has connection to controlling terminal.
Even if doing setsid via flag it's still not clear if user want the new process to be a session leader (i.e. call setsid in the second fork) or not (call setsid in the first fork and let it die).

It may be worth leaving it for a separate PR.

So shall I remove setsid for now?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification. I think I'm out of my depth here. Perhaps someone more knowledgeable than me about POSIX process sessions can chime in, @kyllingstad @schveiguy @jmdavis ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've done some experiments. Login via ssh (just plain login without tmux, screen or similar) and spawned some script process in detached state without calling to setsid. Logout and re-login again, the process still ran. So I guess setsid is not necessary after all.

std/process.d Outdated
}

private:
@property bool owned() const @safe pure nothrow
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No point in a private property, just name the field owned.

std/process.d Outdated
This leads to the annoying message like "/bin/sh: 0: Can't open /tmp/std.process temporary file" to appear when running tests.
It does not happen in unittests with non-detached processes because we always wait() for them to finish.
*/
Thread.sleep(dur!"msecs"(5));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fine, but I'd give it a more generous timeout of 100 msecs or so just to exclude race conditions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used 5 msecs, because there's the same sleep in the other unittest under version(Android), having a comment about Android killing sleeping applications.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine, we don't have CI for Android; I'm more concerned about Windows, where process creation is very slow. If the Android maintainer finds that this test is causing them trouble then they can fix it as needed. (Also, I was pretty sure Android kills idle apps, not processes...)

@dlang-bot
Copy link
Contributor

dlang-bot commented Jun 25, 2017

Thanks for your pull request, @FreeSlave! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.

Some tips to help speed things up:

  • smaller, focused PRs are easier to review than big ones

  • try not to mix up refactoring or style changes with bug fixes or feature enhancements

  • provide helpful commit messages explaining the rationale behind each change

Bear in mind that large or tricky changes may require multiple rounds of review and revision.

Please see CONTRIBUTING.md for more information.

Bugzilla references

Fix Bugzilla Description
17519 RedBlackTree doesn't like const/immutable elements

@CyberShadow
Copy link
Member

Could you please rebase on top of the latest master? That should fix CircleCI.

@FreeSlave FreeSlave force-pushed the spawnProcessDetached branch from 07578c0 to fb3ff62 Compare June 26, 2017 07:15
@FreeSlave
Copy link
Contributor Author

Rebased. Is any other change needed?

@CyberShadow
Copy link
Member

Ah, a changelog entry or linked bug as per @dlang-bot's comment. I think that's all if there is no further feedback.

@FreeSlave
Copy link
Contributor Author

FreeSlave commented Jun 26, 2017

I've added changelog FreeSlave@fa8a73f, but github does not see the changes. Probably because of the previous rebase.
Upd: it was resolved.

@CyberShadow
Copy link
Member

@wilzbach Any idea why changelog is not showing up in DAutoTest diff here?

@wilzbach
Copy link
Contributor

@wilzbach Any idea why changelog is not showing up in DAutoTest diff here?

Yes, it seems like Martin has added this file and thus it doesn't get generated:

https://github.com/dlang/dlang.org/blob/master/changelog/2.075.0_pre.dd

Should we bump the version at dlang.org? Probably a good idea to do this for all version files after the master -> stable branch-off?

@CyberShadow
Copy link
Member

Should we bump the version at dlang.org? Probably a good idea to do this for all version files after the master -> stable branch-off?

Sounds like a good idea.

@JackStouffer JackStouffer requested a review from andralex July 3, 2017 18:28

Config.detached allows to $(REF_ALTTEXT spawn process, spawnProcess, std, process) independently from the caller.
No need to wait on the process spawned that way - no zombie will left after process exits.
Attempts to $(REF wait, std, process) on or $(REF kill, std, process) detached processes will throw.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some copyediting:

Config.detached allows $(REF_ALTTEXT spawning processes, spawnProcess, std, process) which run independently from the current process. There is no need to wait on the processes created with this flag, and no $(HTTPS en.wikipedia.org/wiki/Zombie_process, zombie process) will be left after they exit.
Attempts to call $(REF wait, std, process) or $(REF kill, std, process) on detached processes will throw.

@JackStouffer
Copy link
Contributor

Does this really need Andrei's approval? It doesn't really add a new symbol.

@wilzbach
Copy link
Contributor

Does this really need Andrei's approval? It doesn't really add a new symbol.

Well there's Config.detached, but yeah I'm a bit frustrated about the huge bottleneck that this is causing as well. Maybe

  • we should let the bot send @andralex a mail every week about open PRs which require his approval
  • move away from this single point of failure and redefine this policy to "at least two codeowners need to approve a new symbol" (or require the @andralex label only for modules he cares about, i.e. for which he is a code owner)

std/process.d Outdated
chdir,
getrlimit
getrlimit,
doubleFork
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a comma so the next addition blames properly

std/process.d Outdated
// but we don't have a direct access to the second fork pid from the caller side thus use a pipe.
// We also can't reuse forkPipe for that purpose
// because we can't predict the order in which pid and possible error will be written
// since the first and the second forks will run in parallel.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like a multiline comment

if (core.sys.posix.unistd.pipe(pidPipe) == 0)
setCLOEXEC(pidPipe[1], true);
else
throw ProcessException.newFromErrno("Could not create pipe to get process pid");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplify flow:

if (core.sys.posix.unistd.pipe(pidPipe) != 0)
    throw ...;
setCLOEXEC(pidPipe[1], true);

else
throw ProcessException.newFromErrno("Could not create pipe to get process pid");
}
scope(exit) if (config & Config.detached) close(pidPipe[0]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make these considerations a nice comment

std/process.d Outdated
// In the case that stderr is redirected to stdout, we need
// to backup the file descriptor since stdout may be redirected
// as well.
if (stderrFD == STDOUT_FILENO) stderrFD = dup(stderrFD);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

double space?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was like this in previous implementation

std/process.d Outdated
immutable maxToClose = maxDescriptors - 3;

// Call poll() to see which ones are actually open:
pollfd* pfds = cast(pollfd*) malloc(pollfd.sizeof * maxToClose);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

auto

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, you're asking to change things that were like this before me. Well, I can, for sure.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and much appreciated!

std/process.d Outdated
auto status = InternalError.noerror;
auto readExecResult = core.sys.posix.unistd.read(forkPipe[0], &status, status.sizeof);
// Save error number just in case if subsequent "waitpid" fails and overrides errno
auto lastError = .errno;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

immutable

std/process.d Outdated

if (readExecResult == error.sizeof)
throw ProcessException.newFromErrno(error, errorMsg);
else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete

if (read(pidPipe[0], &actualPid, id.sizeof) == id.sizeof)
id = actualPid;
else
throw ProcessException.newFromErrno("Could not read from pipe to get detached process id");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simplify flow

std/process.d Outdated
CloseHandle(pi.hProcess);
return new Pid(pi.dwProcessId);
}
else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

felete

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete? ;)

Copy link
Contributor Author

@FreeSlave FreeSlave Jul 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete what? Can you elaborate? Oh, you mean just else. Got it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean delete the else line.

@andralex
Copy link
Member

move away from this single point of failure and redefine this policy to "at least two codeowners need to approve a new symbol" (or require the @andralex label only for modules he cares about, i.e. for which he is a code owner)

Please let me be the point of failure for the sake of better checks and balances of library consistency. In several prior cases it has happened that design sensibilities somewhat foreign to D/Phobos have entered the standard library, to everybody's displeasure. Thanks.

Copy link
Member

@schveiguy schveiguy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I would just tweak the timing a bit. There's no guarantee on how long a process takes to finish, especially on a busy OS, and losing a few seconds in the time to test phobos isn't going to kill us.

std/process.d Outdated
CloseHandle(pi.hProcess);
return new Pid(pi.dwProcessId);
}
else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete? ;)

std/process.d Outdated
wait(pid);
else
// We need to wait a little to ensure that the process has finished and data was written to files
Thread.sleep(dur!"msecs"(200));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait longer. There's no need to vie for performance here. Wait 2 seconds instead of .2

Copy link
Member

@schveiguy schveiguy Jul 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, stylistic change, you can put 2.seconds instead of dur!"seconds"(2)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer unittests run as fast as they could. But ok.

std/process.d Outdated
This leads to the annoying message like "/bin/sh: 0: Can't open /tmp/std.process temporary file" to appear when running tests.
It does not happen in unittests with non-detached processes because we always wait() for them to finish.
*/
Thread.sleep(dur!"msecs"(100));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Longer time here too.

Copy link
Member

@andralex andralex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok with the addition, leaving detailed reviews to @schveiguy and others

@schveiguy
Copy link
Member

ping @CyberShadow any idea why the DAutoTest fails?

@schveiguy
Copy link
Member

Bugzilla references

@wilzbach this looks invalid to me, this has nothing to do with RedBlackTree. I don't actually see a bugzilla reference in any commit, so not sure why this showed up.

@CyberShadow
Copy link
Member

ping @CyberShadow any idea why the DAutoTest fails?

Please see #5639 (comment) / #5626 (comment) / #5625 (comment) / #5619 (comment) / #5617 (comment).

TL;DR: GitHub bug.

@schveiguy
Copy link
Member

@CyberShadow thanks, here's a followup: while this bug exists, what is the correct response, seeing as that test is required for merging? Should I just ping you/@wilzbach, or is there a way I can fix it myself?

@wilzbach
Copy link
Contributor

while this bug exists, what is the correct response, seeing as that test is required for merging? Should I just ping you/@wilzbach, or is there a way I can fix it myself?

AFAICT the only safe way is to create a new PR.
It also needs to be a different commit sha :/

We can overwrite it manually if the auto-tester passes, but there is always the slight risk of breaking Jenkins or CircleCI though. However, at least for CircleCi we get a warning mail afterwards, so I think we can start to risk it. Creating a new PR all the time, is really annoying.

@wilzbach
Copy link
Contributor

@wilzbach this looks invalid to me, this has nothing to do with RedBlackTree. I don't actually see a bugzilla reference in any commit, so not sure why this showed up.

I would guess that it's due to the GitHub API sending rubbish.

@wilzbach wilzbach merged commit fe89346 into dlang:master Jul 25, 2017
@wilzbach
Copy link
Contributor

We can overwrite it manually if the auto-tester passes, but there is always the slight risk of breaking Jenkins or CircleCI though. However, at least for CircleCi we get a warning mail afterwards, so I think we can start to risk it. Creating a new PR all the time, is really annoying.

Tried it this time - let's hope for the best. We really need to get GitHub to fix their bugs though..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants